/* * 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, 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 ------------------------------------------------------------*/