/* * 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/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/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"; } 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 --------------------------------------------------------*/ 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); 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 = ", "; } } 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; 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 | 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]; } 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]; } 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; if (s->calling_party) { fsk_rx_spec = &preset_fsk_specs[FSK_BELL202]; fsk_tx_spec = &preset_fsk_specs[FSK_BELL202]; } else { 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]; } 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 } 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; 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); 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; 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; len += s->tx_handler(s->tx_user_data, &[len], max_len - len); } return len; } /*- 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, put_msg_func_t put_msg, get_msg_func_t get_msg, void *user_data) { if (s == NULL) { if ((s = (data_modems_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, "Modem"); dc_restore_init(&s->dc_restore); 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); 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); return 0; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/