From ab59a26a519d4bfb88f9ca6f882da8baab90a95a Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 18 Nov 2017 08:33:07 +0100 Subject: Restructure: Move mobile from common code to 'libmobile' --- .gitignore | 2 +- configure.ac | 1 + src/Makefile.am | 1 + src/amps/Makefile.am | 2 +- src/amps/amps.c | 2 +- src/amps/amps.h | 2 +- src/amps/amps_tacs_main.c | 4 +- src/amps/dsp.c | 2 +- src/amps/transaction.c | 2 +- src/anetz/Makefile.am | 2 +- src/anetz/anetz.c | 2 +- src/anetz/anetz.h | 2 +- src/anetz/dsp.c | 2 +- src/anetz/main.c | 4 +- src/bnetz/Makefile.am | 2 +- src/bnetz/bnetz.c | 2 +- src/bnetz/bnetz.h | 2 +- src/bnetz/dsp.c | 2 +- src/bnetz/main.c | 4 +- src/cnetz/Makefile.am | 2 +- src/cnetz/cnetz.c | 2 +- src/cnetz/cnetz.h | 2 +- src/cnetz/dsp.c | 2 +- src/cnetz/main.c | 4 +- src/cnetz/transaction.c | 2 +- src/common/Makefile.am | 8 +- src/common/call.c | 790 ------------------------------------- src/common/call.h | 40 -- src/common/display_measurements.c | 2 +- src/common/display_status.c | 147 ------- src/common/display_wave.c | 2 +- src/common/main_mobile.c | 688 -------------------------------- src/common/main_mobile.h | 45 --- src/common/sender.c | 449 --------------------- src/common/sender.h | 101 ----- src/jtacs/Makefile.am | 2 +- src/libmncc/mncc_console.c | 2 +- src/libmncc/mncc_cross.c | 2 +- src/libmncc/mncc_sock.c | 2 +- src/libmobile/Makefile.am | 14 + src/libmobile/call.c | 796 ++++++++++++++++++++++++++++++++++++++ src/libmobile/call.h | 40 ++ src/libmobile/display_status.c | 147 +++++++ src/libmobile/main_mobile.c | 688 ++++++++++++++++++++++++++++++++ src/libmobile/main_mobile.h | 45 +++ src/libmobile/sender.c | 449 +++++++++++++++++++++ src/libmobile/sender.h | 101 +++++ src/libsdr/display_iq.c | 2 +- src/libsdr/display_spectrum.c | 2 +- src/libsdr/sdr.c | 2 +- src/libsound/sound_alsa.c | 2 +- src/nmt/Makefile.am | 2 +- src/nmt/main.c | 2 +- src/nmt/nmt.h | 4 +- src/r2000/Makefile.am | 2 +- src/r2000/main.c | 2 +- src/r2000/r2000.h | 4 +- src/tacs/Makefile.am | 2 +- src/test/Makefile.am | 14 +- 59 files changed, 2336 insertions(+), 2320 deletions(-) delete mode 100644 src/common/call.c delete mode 100644 src/common/call.h delete mode 100644 src/common/display_status.c delete mode 100644 src/common/main_mobile.c delete mode 100644 src/common/main_mobile.h delete mode 100644 src/common/sender.c delete mode 100644 src/common/sender.h create mode 100644 src/libmobile/Makefile.am create mode 100644 src/libmobile/call.c create mode 100644 src/libmobile/call.h create mode 100644 src/libmobile/display_status.c create mode 100644 src/libmobile/main_mobile.c create mode 100644 src/libmobile/main_mobile.h create mode 100644 src/libmobile/sender.c create mode 100644 src/libmobile/sender.h diff --git a/.gitignore b/.gitignore index 1ddc793..13791ad 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ compile .libs .dirstamp m4 +src/libmobile/libmobile.a src/libimage/libimage.a src/libcompandor/libcompandor.a src/libgoertzel/libgoertzel.a @@ -41,7 +42,6 @@ src/libsound/libsound.a src/libsdr/libsdr.a src/libsample/libsample.a src/common/libcommon.a -src/common/libmobile.a src/anetz/libgermanton.a src/anetz/anetz src/bnetz/bnetz diff --git a/configure.ac b/configure.ac index 2cd920b..5da06a3 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,7 @@ AS_IF([test "x$with_soapy" == "xyes"],[AC_MSG_NOTICE( Compiling with SoapySDR su AS_IF([test "x$somethingmagick" == "xyes"],[AC_MSG_NOTICE( Compiling with ImageMagick )],[AC_MSG_NOTICE( ImageMagick not supported )]) AC_OUTPUT( + src/libmobile/Makefile src/libimage/Makefile src/libcompandor/Makefile src/libgoertzel/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index ff58c84..d96b041 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,7 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = \ + libmobile \ libsample \ libimage \ libcompandor \ diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am index 88da1cb..1dab22b 100644 --- a/src/amps/Makefile.am +++ b/src/amps/Makefile.am @@ -26,10 +26,10 @@ amps_SOURCES = \ amps_LDADD = \ $(COMMON_LA) \ libamps.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/amps/amps.c b/src/amps/amps.c index de9cac2..63ac076 100644 --- a/src/amps/amps.c +++ b/src/amps/amps.c @@ -44,7 +44,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libmncc/cause.h" #include "amps.h" #include "dsp.h" diff --git a/src/amps/amps.h b/src/amps/amps.h index 445675e..9087be5 100644 --- a/src/amps/amps.h +++ b/src/amps/amps.h @@ -1,5 +1,5 @@ #include "../libgoertzel/goertzel.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" #include "../libtimer/timer.h" #include "../libcompandor/compandor.h" #include "sysinfo.h" diff --git a/src/amps/amps_tacs_main.c b/src/amps/amps_tacs_main.c index dbb9973..28f7d0c 100644 --- a/src/amps/amps_tacs_main.c +++ b/src/amps/amps_tacs_main.c @@ -23,9 +23,9 @@ #include #include #include "../libsample/sample.h" -#include "../common/main_mobile.h" +#include "../libmobile/main_mobile.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "amps.h" #include "dsp.h" #include "frame.h" diff --git a/src/amps/dsp.c b/src/amps/dsp.c index ae71432..8873026 100644 --- a/src/amps/dsp.c +++ b/src/amps/dsp.c @@ -83,7 +83,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "amps.h" #include "frame.h" #include "dsp.h" diff --git a/src/amps/transaction.c b/src/amps/transaction.c index edad0a3..7e1ff2c 100644 --- a/src/amps/transaction.c +++ b/src/amps/transaction.c @@ -22,7 +22,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libmncc/cause.h" #include "amps.h" //#include "database.h" diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am index fb92754..d15024f 100644 --- a/src/anetz/Makefile.am +++ b/src/anetz/Makefile.am @@ -18,10 +18,10 @@ anetz_SOURCES = \ anetz_LDADD = \ $(COMMON_LA) \ libgermanton.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libsquelch/libsquelch.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/anetz/anetz.c b/src/anetz/anetz.c index 077d673..899cc80 100644 --- a/src/anetz/anetz.c +++ b/src/anetz/anetz.c @@ -27,7 +27,7 @@ #include "../libsample/sample.h" #include "../common/debug.h" #include "../libtimer/timer.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libmncc/cause.h" #include "anetz.h" #include "dsp.h" diff --git a/src/anetz/anetz.h b/src/anetz/anetz.h index 9303280..9a813cd 100644 --- a/src/anetz/anetz.h +++ b/src/anetz/anetz.h @@ -1,6 +1,6 @@ #include "../libsquelch/squelch.h" #include "../libgoertzel/goertzel.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" enum dsp_mode { DSP_MODE_SILENCE, /* send silence to transmitter, block audio from receiver */ diff --git a/src/anetz/dsp.c b/src/anetz/dsp.c index ec971fc..fed1613 100644 --- a/src/anetz/dsp.c +++ b/src/anetz/dsp.c @@ -28,7 +28,7 @@ #include "../libsample/sample.h" #include "../common/debug.h" #include "../libtimer/timer.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "anetz.h" #include "dsp.h" diff --git a/src/anetz/main.c b/src/anetz/main.c index 382ccc4..825c4e9 100644 --- a/src/anetz/main.c +++ b/src/anetz/main.c @@ -24,10 +24,10 @@ #include #include #include "../libsample/sample.h" -#include "../common/main_mobile.h" +#include "../libmobile/main_mobile.h" #include "../common/debug.h" #include "../libtimer/timer.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "freiton.h" #include "besetztton.h" #include "anetz.h" diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am index 5a98339..5571b11 100644 --- a/src/bnetz/Makefile.am +++ b/src/bnetz/Makefile.am @@ -14,9 +14,9 @@ bnetz_SOURCES = \ bnetz_LDADD = \ $(COMMON_LA) \ ../anetz/libgermanton.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libsquelch/libsquelch.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/bnetz/bnetz.c b/src/bnetz/bnetz.c index cd78db0..21ef024 100644 --- a/src/bnetz/bnetz.c +++ b/src/bnetz/bnetz.c @@ -26,7 +26,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libmncc/cause.h" #include "bnetz.h" #include "telegramm.h" diff --git a/src/bnetz/bnetz.h b/src/bnetz/bnetz.h index 631fb27..34fa93f 100644 --- a/src/bnetz/bnetz.h +++ b/src/bnetz/bnetz.h @@ -1,6 +1,6 @@ #include "../libsquelch/squelch.h" #include "../libfsk/fsk.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" #include "../libtimer/timer.h" /* fsk modes of transmission */ diff --git a/src/bnetz/dsp.c b/src/bnetz/dsp.c index 01326ef..b3d1599 100644 --- a/src/bnetz/dsp.c +++ b/src/bnetz/dsp.c @@ -27,7 +27,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "bnetz.h" #include "dsp.h" diff --git a/src/bnetz/main.c b/src/bnetz/main.c index 014165b..68d1359 100644 --- a/src/bnetz/main.c +++ b/src/bnetz/main.c @@ -25,8 +25,8 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" -#include "../common/main_mobile.h" +#include "../libmobile/call.h" +#include "../libmobile/main_mobile.h" #include "../anetz/freiton.h" #include "../anetz/besetztton.h" #include "bnetz.h" diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am index 6c1164e..2cb0b86 100644 --- a/src/cnetz/Makefile.am +++ b/src/cnetz/Makefile.am @@ -17,9 +17,9 @@ cnetz_SOURCES = \ cnetz_LDADD = \ $(COMMON_LA) \ ../anetz/libgermanton.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/cnetz/cnetz.c b/src/cnetz/cnetz.c index d8a9ccf..c34397d 100644 --- a/src/cnetz/cnetz.c +++ b/src/cnetz/cnetz.c @@ -144,7 +144,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libmncc/cause.h" #include "cnetz.h" #include "database.h" diff --git a/src/cnetz/cnetz.h b/src/cnetz/cnetz.h index 55b5d2b..9b2323f 100644 --- a/src/cnetz/cnetz.h +++ b/src/cnetz/cnetz.h @@ -1,6 +1,6 @@ #include "../libcompandor/compandor.h" #include "../libtimer/timer.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" #include "fsk_demod.h" #include "../libscrambler/scrambler.h" #include "transaction.h" diff --git a/src/cnetz/dsp.c b/src/cnetz/dsp.c index cba0de9..30d7372 100644 --- a/src/cnetz/dsp.c +++ b/src/cnetz/dsp.c @@ -27,7 +27,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "cnetz.h" #include "sysinfo.h" #include "telegramm.h" diff --git a/src/cnetz/main.c b/src/cnetz/main.c index 3285fee..d1b9a38 100644 --- a/src/cnetz/main.c +++ b/src/cnetz/main.c @@ -23,9 +23,9 @@ #include #include #include "../libsample/sample.h" -#include "../common/main_mobile.h" +#include "../libmobile/main_mobile.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../anetz/freiton.h" #include "../anetz/besetztton.h" #include "cnetz.h" diff --git a/src/cnetz/transaction.c b/src/cnetz/transaction.c index 724fe9e..b26b642 100644 --- a/src/cnetz/transaction.c +++ b/src/cnetz/transaction.c @@ -22,7 +22,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libmncc/cause.h" #include "cnetz.h" #include "telegramm.h" diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 8380053..879307c 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -1,18 +1,12 @@ AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) -noinst_LIBRARIES = libcommon.a libmobile.a +noinst_LIBRARIES = libcommon.a libcommon_a_SOURCES = \ debug.c \ display_wave.c \ display_measurements.c -libmobile_a_SOURCES = \ - sender.c \ - call.c \ - display_status.c \ - main_mobile.c - if HAVE_SDR AM_CPPFLAGS += -DHAVE_SDR endif diff --git a/src/common/call.c b/src/common/call.c deleted file mode 100644 index 85c0e9f..0000000 --- a/src/common/call.c +++ /dev/null @@ -1,790 +0,0 @@ -/* interface between mobile network/phone implementation and MNCC - * - * (C) 2016 by Andreas Eversberg - * 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 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include "../libsample/sample.h" -#include "debug.h" -#include "sender.h" -#include "call.h" -#include "../libtimer/timer.h" -#include "../libmncc/mncc.h" -#include "../libmncc/cause.h" - -#define DISC_TIMEOUT 30 - -//#define DEBUG_LEVEL - -#ifdef DEBUG_LEVEL -static double level_of(double *samples, int count) -{ - double level = 0; - int i; - - for (i = 0; i < count; i++) { - if (samples[i] > level) - level = samples[i]; - } - - return level; -} -#endif - -static int send_patterns; /* send patterns towards fixed network */ -static int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */ - -/* stream patterns/announcements */ -int16_t *ringback_spl = NULL; -int ringback_size = 0; -int ringback_max = 0; -int16_t *hangup_spl = NULL; -int hangup_size = 0; -int hangup_max = 0; -int16_t *busy_spl = NULL; -int busy_size = 0; -int busy_max = 0; -int16_t *noanswer_spl = NULL; -int noanswer_size = 0; -int noanswer_max = 0; -int16_t *outoforder_spl = NULL; -int outoforder_size = 0; -int outoforder_max = 0; -int16_t *invalidnumber_spl = NULL; -int invalidnumber_size = 0; -int invalidnumber_max = 0; -int16_t *congestion_spl = NULL; -int congestion_size = 0; -int congestion_max = 0; -int16_t *recall_spl = NULL; -int recall_size = 0; -int recall_max = 0; - -enum audio_pattern { - PATTERN_NONE = 0, - PATTERN_TEST, - PATTERN_RINGBACK, - PATTERN_HANGUP, - PATTERN_BUSY, - PATTERN_NOANSWER, - PATTERN_OUTOFORDER, - PATTERN_INVALIDNUMBER, - PATTERN_CONGESTION, - PATTERN_RECALL, -}; - -static void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern) -{ - *spl = NULL; - *size = 0; - *max = 0; - - switch (pattern) { - case PATTERN_RINGBACK: -no_recall: - *spl = ringback_spl; - *size = ringback_size; - *max = ringback_max; - break; - case PATTERN_HANGUP: - if (!hangup_spl) - goto no_hangup; - *spl = hangup_spl; - *size = hangup_size; - *max = hangup_max; - break; - case PATTERN_BUSY: -no_hangup: -no_noanswer: - *spl = busy_spl; - *size = busy_size; - *max = busy_max; - break; - case PATTERN_NOANSWER: - if (!noanswer_spl) - goto no_noanswer; - *spl = noanswer_spl; - *size = noanswer_size; - *max = noanswer_max; - break; - case PATTERN_OUTOFORDER: - if (!outoforder_spl) - goto no_outoforder; - *spl = outoforder_spl; - *size = outoforder_size; - *max = outoforder_max; - break; - case PATTERN_INVALIDNUMBER: - if (!invalidnumber_spl) - goto no_invalidnumber; - *spl = invalidnumber_spl; - *size = invalidnumber_size; - *max = invalidnumber_max; - break; - case PATTERN_CONGESTION: -no_outoforder: -no_invalidnumber: - *spl = congestion_spl; - *size = congestion_size; - *max = congestion_max; - break; - case PATTERN_RECALL: - if (!recall_spl) - goto no_recall; - *spl = recall_spl; - *size = recall_size; - *max = recall_max; - break; - default: - ; - } -} - -static enum audio_pattern cause2pattern(int cause) -{ - int pattern; - - switch (cause) { - case CAUSE_NORMAL: - pattern = PATTERN_HANGUP; - break; - case CAUSE_BUSY: - pattern = PATTERN_BUSY; - break; - case CAUSE_NOANSWER: - pattern = PATTERN_NOANSWER; - break; - case CAUSE_OUTOFORDER: - pattern = PATTERN_OUTOFORDER; - break; - case CAUSE_INVALNUMBER: - pattern = PATTERN_INVALIDNUMBER; - break; - case CAUSE_NOCHANNEL: - pattern = PATTERN_CONGESTION; - break; - default: - pattern = PATTERN_HANGUP; - } - - return pattern; -} - -enum process_state { - PROCESS_IDLE = 0, /* IDLE */ - PROCESS_SETUP_RO, /* call from radio to MNCC */ - PROCESS_SETUP_RT, /* call from MNCC to radio */ - PROCESS_ALERTING_RO, /* call from radio to MNCC */ - PROCESS_ALERTING_RT, /* call from MNCC to radio */ - PROCESS_CONNECT, - PROCESS_DISCONNECT, -}; - -/* MNCC call instance */ -typedef struct process { - struct process *next; - int callref; - enum process_state state; - int audio_disconnected; /* if not associated with transceiver anymore */ - enum audio_pattern pattern; - int audio_pos; - uint8_t cause; - struct timer timer; -} process_t; - -static process_t *process_head = NULL; - -static void process_timeout(struct timer *timer); - -static process_t *create_process(int callref, enum process_state state) -{ - process_t *process; - - process = calloc(sizeof(*process), 1); - if (!process) { - PDEBUG(DCALL, DEBUG_ERROR, "No memory!\n"); - abort(); - } - timer_init(&process->timer, process_timeout, process); - process->next = process_head; - process_head = process; - - process->callref = callref; - process->state = state; - - return process; -} - -static void destroy_process(int callref) -{ - process_t *process = process_head; - process_t **process_p = &process_head; - - while (process) { - if (process->callref == callref) { - *process_p = process->next; - timer_exit(&process->timer); - free(process); - return; - } - process_p = &process->next; - process = process->next; - } - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); -} - -static process_t *get_process(int callref) -{ - process_t *process = process_head; - - while (process) { - if (process->callref == callref) - return process; - process = process->next; - } - return NULL; -} - -static void new_state_process(int callref, enum process_state state) -{ - process_t *process = get_process(callref); - - if (!process) { - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); - return; - } - process->state = state; -} - -static void set_pattern_process(int callref, enum audio_pattern pattern) -{ - process_t *process = get_process(callref); - - if (!process) { - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); - return; - } - process->pattern = pattern; - process->audio_pos = 0; -} - -/* disconnect audio, now send audio directly from pattern/announcement, not from transceiver */ -static void disconnect_process(int callref, int cause) -{ - process_t *process = get_process(callref); - - if (!process) { - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); - return; - } - process->pattern = cause2pattern(cause); - process->audio_disconnected = 1; - process->audio_pos = 0; - process->cause = cause; - timer_start(&process->timer, DISC_TIMEOUT); -} - -static void get_process_patterns(process_t *process, int16_t *samples, int length) -{ - const int16_t *spl; - int size, max, pos; - - get_pattern(&spl, &size, &max, process->pattern); - - /* stream sample */ - pos = process->audio_pos; - while(length--) { - if (pos >= size) - *samples++ = 0; - else - *samples++ = spl[pos] >> 1; - if (++pos == max) - pos = 0; - } - process->audio_pos = pos; -} - -static void process_timeout(struct timer *timer) -{ - process_t *process = (process_t *)timer->priv; - - { - /* announcement timeout */ - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_REL_IND; - mncc->callref = process->callref; - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.location = LOCATION_PRIVATE_LOCAL; - mncc->cause.value = process->cause; - - destroy_process(process->callref); - PDEBUG(DCALL, DEBUG_INFO, "Releasing MNCC call towards fixed network (after timeout)\n"); - mncc_up(buf, sizeof(struct gsm_mncc)); - } -} - -int call_init(int _send_patterns, int _release_on_disconnect) -{ - send_patterns = _send_patterns; - release_on_disconnect = _release_on_disconnect; - - return 0; -} - -/* Setup is received from transceiver. */ -static int _indicate_setup(int callref, const char *callerid, const char *dialing) -{ - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - int rc; - - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_SETUP_IND; - mncc->callref = callref; - mncc->fields |= MNCC_F_CALLING; - if (callerid) { - strncpy(mncc->calling.number, callerid, sizeof(mncc->calling.number) - 1); - mncc->calling.type = 4; /* caller ID is of type 'subscriber' */ - } // otherwise unknown and no number - mncc->fields |= MNCC_F_CALLED; - strncpy(mncc->called.number, dialing, sizeof(mncc->called.number) - 1); - mncc->called.type = 0; /* dialing is of type 'unknown' */ - mncc->lchan_type = GSM_LCHAN_TCH_F; - mncc->fields |= MNCC_F_BEARER_CAP; - mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; - mncc->bearer_cap.speech_ver[1] = -1; - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup towards fixed network\n"); - rc = mncc_up(buf, sizeof(struct gsm_mncc)); - if (rc < 0) - destroy_process(callref); - return rc; -} -int call_up_setup(int callref, const char *callerid, const char *dialing) -{ - int rc; - - if (!callref) { - PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring setup, because callref not set. (not for us)\n"); - return -CAUSE_INVALCALLREF; - } - - if (callref < 0x4000000) { - PDEBUG(DCALL, DEBUG_ERROR, "Invalid callref from mobile station, please fix!\n"); - abort(); - } - - PDEBUG(DCALL, DEBUG_INFO, "Incoming call from '%s' to '%s'\n", callerid ? : "unknown", dialing); - if (!strcmp(dialing, "010")) - PDEBUG(DCALL, DEBUG_INFO, " -> Call to Operator '%s'\n", dialing); - - - create_process(callref, PROCESS_SETUP_RO); - - rc = _indicate_setup(callref, callerid, dialing); - - return rc; -} - -/* Transceiver indicates alerting. */ -static void _indicate_alerting(int callref) -{ - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - int rc; - - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_ALERT_IND; - mncc->callref = callref; - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC alerting towards fixed network\n"); - rc = mncc_up(buf, sizeof(struct gsm_mncc)); - if (rc < 0) - destroy_process(callref); -} -void call_up_alerting(int callref) -{ - if (!callref) { - PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring alerting, because callref not set. (not for us)\n"); - return; - } - - PDEBUG(DCALL, DEBUG_INFO, "Call is alerting\n"); - - if (!send_patterns) - _indicate_alerting(callref); - set_pattern_process(callref, PATTERN_RINGBACK); - new_state_process(callref, PROCESS_ALERTING_RT); -} - -/* Transceiver indicates answer. */ -static void _indicate_answer(int callref, const char *connect_id) -{ - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - int rc; - - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_SETUP_CNF; - mncc->callref = callref; - mncc->fields |= MNCC_F_CONNECTED; - /* copy connected number as subscriber number */ - strncpy(mncc->connected.number, connect_id, sizeof(mncc->connected.number)); - mncc->connected.type = 4; - mncc->connected.plan = 1; - mncc->connected.present = 0; - mncc->connected.screen = 3; - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC answer towards fixed network\n"); - rc = mncc_up(buf, sizeof(struct gsm_mncc)); - if (rc < 0) - destroy_process(callref); -} -void call_up_answer(int callref, const char *connect_id) -{ - if (!callref) { - PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring answer, because callref not set. (not for us)\n"); - return; - } - - PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connect_id); - - if (!send_patterns) - _indicate_answer(callref, connect_id); - set_pattern_process(callref, PATTERN_NONE); - new_state_process(callref, PROCESS_CONNECT); -} - -/* Transceiver indicates release. */ -static void _indicate_disconnect_release(int callref, int cause, int disc) -{ - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - int rc; - - memset(buf, 0, sizeof(buf)); - mncc->msg_type = (disc) ? MNCC_DISC_IND : MNCC_REL_IND; - mncc->callref = callref; - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.location = LOCATION_PRIVATE_LOCAL; - mncc->cause.value = cause; - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC %s towards fixed network\n", (disc) ? "disconnect" : "release"); - rc = mncc_up(buf, sizeof(struct gsm_mncc)); - if (rc < 0) - destroy_process(callref); -} -void call_up_release(int callref, int cause) -{ - process_t *process; - - if (!callref) { - PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring release, because callref not set. (not for us)\n"); - return; - } - - PDEBUG(DCALL, DEBUG_INFO, "Call has been released with cause=%d\n", cause); - - process = get_process(callref); - if (process) { - /* just keep MNCC connection if tones shall be sent. - * no tones while setting up / alerting the call. */ - if (send_patterns - && process->state != PROCESS_SETUP_RO - && process->state != PROCESS_ALERTING_RO) - disconnect_process(callref, cause); - else - /* if no tones shall be sent, release on disconnect - * or RO setup states */ - if (process->state == PROCESS_DISCONNECT - || process->state == PROCESS_SETUP_RO - || process->state == PROCESS_ALERTING_RO) { - destroy_process(callref); - _indicate_disconnect_release(callref, cause, 0); - /* if no tones shall be sent, disconnect on all other states */ - } else { - disconnect_process(callref, cause); - _indicate_disconnect_release(callref, cause, 1); - } - } else { - /* we don't know about the process, just send release to upper layer anyway */ - _indicate_disconnect_release(callref, cause, 0); - } -} - -/* turn recall tone on or off */ -void call_tone_recall(int callref, int on) -{ - set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE); -} - -/* forward audio to MNCC or call instance */ -void call_up_audio(int callref, sample_t *samples, int count) -{ - if (count != 160) { - fprintf(stderr, "Samples must be 160, please fix!\n"); - abort(); - } - /* is MNCC us used, forward audio */ - uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; - struct gsm_data_frame *data = (struct gsm_data_frame *)buf; - process_t *process; - - if (!callref) - return; - - /* if we are disconnected, ignore audio */ - process = get_process(callref); - if (!process || process->pattern != PATTERN_NONE) - return; - - /* forward audio */ - data->msg_type = ANALOG_8000HZ; - data->callref = callref; -#ifdef DEBUG_LEVEL - double lev = level_of(samples, count); - printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); -#endif - samples_to_int16((int16_t *)data->data, samples, count); - - mncc_up(buf, sizeof(buf)); - /* don't destroy process here in case of an error */ -} - -/* clock that is used to transmit patterns */ -void call_clock(void) -{ - process_t *process = process_head; - uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; - struct gsm_data_frame *data = (struct gsm_data_frame *)buf; - - while(process) { - if (process->pattern != PATTERN_NONE) { - data->msg_type = ANALOG_8000HZ; - data->callref = process->callref; - /* try to get patterns, else copy the samples we got */ - get_process_patterns(process, (int16_t *)data->data, 160); -#ifdef DEBUG_LEVEL - sample_t samples[160]; - int16_to_samples(samples, (int16_t *)data->data, 160); - double lev = level_of(samples, 160); - printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); - samples_to_int16((int16_t *)data->data, samples, 160); -#endif - mncc_up(buf, sizeof(buf)); - /* don't destroy process here in case of an error */ - } - process = process->next; - } -} - -/* mncc messages received from fixed network */ -void mncc_down(uint8_t *buf, int length) -{ - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - char number[sizeof(mncc->called.number)]; - char caller_id[sizeof(mncc->calling.number)]; - enum number_type caller_type; - int callref; - int rc; - process_t *process; - - callref = mncc->callref; - process = get_process(callref); - if (!process) { - if (mncc->msg_type == MNCC_SETUP_REQ) - process = create_process(callref, PROCESS_SETUP_RT); - else { - if (mncc->msg_type != MNCC_REL_REQ) - PDEBUG(DCALL, DEBUG_ERROR, "No process!\n"); - return; - } - } - - if (mncc->msg_type == ANALOG_8000HZ) { - struct gsm_data_frame *data = (struct gsm_data_frame *)buf; - sample_t samples[160]; - - /* if we are disconnected, ignore audio */ - if (process->pattern != PATTERN_NONE) - return; - int16_to_samples(samples, (int16_t *)data->data, 160); -#ifdef DEBUG_LEVEL - double lev = level_of(samples, 160); - printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev))); -#endif - call_down_audio(callref, samples, 160); - return; - } - - if (process->audio_disconnected) { - switch(mncc->msg_type) { - case MNCC_DISC_REQ: - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value); - - PDEBUG(DCALL, DEBUG_INFO, "Call disconnected, releasing!\n"); - - destroy_process(callref); - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n"); - mncc->msg_type = MNCC_REL_IND; - rc = mncc_up(buf, sizeof(struct gsm_mncc)); - if (rc < 0) - destroy_process(callref); - break; - case MNCC_REL_REQ: - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value); - - PDEBUG(DCALL, DEBUG_INFO, "Call released\n"); - - destroy_process(callref); - break; - } - return; - } - - switch(mncc->msg_type) { - case MNCC_SETUP_REQ: - strcpy(number, mncc->called.number); - - /* caller ID conversion */ - strcpy(caller_id, mncc->calling.number); - switch(mncc->calling.type) { - case 1: - caller_type = TYPE_INTERNATIONAL; - break; - case 2: - caller_type = TYPE_NATIONAL; - break; - case 4: - caller_type = TYPE_SUBSCRIBER; - break; - default: /* or 0 */ - caller_type = TYPE_UNKNOWN; - break; - } - if (!caller_id[0]) - caller_type = TYPE_NOTAVAIL; - if (mncc->calling.present == 1) - caller_type = TYPE_ANONYMOUS; - - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC call from fixed network '%s' to mobile '%s'\n", caller_id, number); - - if (mncc->callref >= 0x4000000) { - fprintf(stderr, "Invalid callref from fixed network, please fix!\n"); - abort(); - } - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC call confirm towards fixed network\n"); - memset(buf, 0, length); - mncc->msg_type = MNCC_CALL_CONF_IND; - mncc->callref = callref; - mncc->lchan_type = GSM_LCHAN_TCH_F; - mncc->fields |= MNCC_F_BEARER_CAP; - mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; - mncc->bearer_cap.speech_ver[1] = -1; - - mncc_up(buf, sizeof(struct gsm_mncc)); - - PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number); - - rc = call_down_setup(callref, caller_id, caller_type, number); - if (rc < 0) { - PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc); - if (send_patterns) { - PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n"); - _indicate_answer(callref, number); - } else { - PDEBUG(DCALL, DEBUG_INFO, "Disconnecting MNCC call towards fixed network (cause=%d)\n", -rc); - _indicate_disconnect_release(callref, -rc, 1); - } - disconnect_process(callref, -rc); - break; - } - - if (send_patterns) { - PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n"); - _indicate_answer(callref, number); - break; - } - break; - case MNCC_ALERT_REQ: - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC alerting from fixed network\n"); - new_state_process(callref, PROCESS_ALERTING_RO); - break; - case MNCC_SETUP_RSP: - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC answer from fixed network\n"); - new_state_process(callref, PROCESS_CONNECT); - PDEBUG(DCALL, DEBUG_INFO, "Call answered\n"); - call_down_answer(callref); - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup complete towards fixed network\n"); - memset(buf, 0, length); - mncc->msg_type = MNCC_SETUP_COMPL_IND; - mncc->callref = callref; - rc = mncc_up(buf, sizeof(struct gsm_mncc)); - if (rc < 0) - destroy_process(callref); - break; - case MNCC_DISC_REQ: - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value); - - process = get_process(callref); - if (process && process->state == PROCESS_CONNECT && release_on_disconnect) { - PDEBUG(DCALL, DEBUG_INFO, "Releasing, because we don't send disconnect tones to mobile phone\n"); - - PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n"); - mncc->msg_type = MNCC_REL_IND; - mncc_up(buf, sizeof(struct gsm_mncc)); - goto release; - } - new_state_process(callref, PROCESS_DISCONNECT); - PDEBUG(DCALL, DEBUG_INFO, "Call disconnected\n"); - call_down_disconnect(callref, mncc->cause.value); - break; - case MNCC_REL_REQ: - PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value); - -release: - destroy_process(callref); - PDEBUG(DCALL, DEBUG_INFO, "Call released\n"); - call_down_release(callref, mncc->cause.value); - break; - } -} - -int (*mncc_up)(uint8_t *buf, int length) = NULL; - -/* break down of MNCC socket */ -void mncc_flush(void) -{ - while(process_head) { - PDEBUG(DCALL, DEBUG_NOTICE, "MNCC socket closed, releasing call\n"); - call_down_release(process_head->callref, CAUSE_TEMPFAIL); - destroy_process(process_head->callref); - /* note: callref is released by sender's instance */ - } -} - diff --git a/src/common/call.h b/src/common/call.h deleted file mode 100644 index 7273a1e..0000000 --- a/src/common/call.h +++ /dev/null @@ -1,40 +0,0 @@ - -/* number type, includes presentation info */ -enum number_type { - TYPE_NOTAVAIL, - TYPE_ANONYMOUS, - TYPE_UNKNOWN, - TYPE_SUBSCRIBER, - TYPE_NATIONAL, - TYPE_INTERNATIONAL, -}; - -int call_init(int _send_patterns, int _release_on_disconnect); - -/* function pointer to delive MNCC messages to upper layer */ -extern int (*mncc_up)(uint8_t *buf, int length); -/* MNCC messages from upper layer */ -void mncc_down(uint8_t *buf, int length); -/* flush all calls in case of MNCC socket failure */ -void mncc_flush(void); - -/* received messages */ -int call_up_setup(int callref, const char *callerid, const char *dialing); -void call_up_alerting(int callref); -void call_up_answer(int callref, const char *connect_id); -void call_up_release(int callref, int cause); -void call_tone_recall(int callref, int on); - -/* send messages */ -int call_down_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing); -void call_down_answer(int callref); -void call_down_disconnect(int callref, int cause); -void call_down_release(int callref, int cause); - -/* send and receive audio */ -void call_up_audio(int callref, sample_t *samples, int count); -void call_down_audio(int callref, sample_t *samples, int count); - -/* clock to transmit to */ -void call_clock(void); - diff --git a/src/common/display_measurements.c b/src/common/display_measurements.c index 07ee5a7..eb8618e 100644 --- a/src/common/display_measurements.c +++ b/src/common/display_measurements.c @@ -25,7 +25,7 @@ #include #include #include "../libsample/sample.h" -#include "sender.h" +#include "../libmobile/sender.h" #define MAX_NAME_LEN 16 #define MAX_UNIT_LEN 16 diff --git a/src/common/display_status.c b/src/common/display_status.c deleted file mode 100644 index 961f294..0000000 --- a/src/common/display_status.c +++ /dev/null @@ -1,147 +0,0 @@ -/* display status functions - * - * (C) 2017 by Andreas Eversberg - * 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 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 . - */ - -#include -#include -#include -#include -#include -#include "../libsample/sample.h" -#include "sender.h" - -static int status_on = 0; -static int line_count = 0; -static int lines_total = 0; -static char screen[MAX_HEIGHT_STATUS][MAX_DISPLAY_WIDTH]; - -static void print_status(int on) -{ - int i, j; - int w, h; - - get_win_size(&w, &h); - - if (w > MAX_DISPLAY_WIDTH) - w = MAX_DISPLAY_WIDTH; - h--; - if (h > lines_total) - h = lines_total; - - printf("\0337\033[H\033[1;37m"); - for (i = 0; i < h; i++) { - j = 0; - if (on) { - for (j = 0; j < w; j++) - putchar(screen[i][j]); - } else { - for (j = 0; j < w; j++) - putchar(' '); - } - putchar('\n'); - } - printf("\0338"); fflush(stdout); -} - -void display_status_on(int on) -{ - if (status_on) - print_status(0); - - if (on < 0) - status_on = 1 - status_on; - else - status_on = on; - - if (status_on) - print_status(1); -} - -void display_status_limit_scroll(int on) -{ - int w, h; - - if (!status_on) - return; - - get_win_size(&w, &h); - - printf("\0337"); - printf("\033[%d;%dr", (on) ? lines_total + 1 : 1, h); - printf("\0338"); -} - -/* start status display */ -void display_status_start(void) -{ - memset(screen, ' ', sizeof(screen)); - memset(screen[0], '-', sizeof(screen[0])); - strncpy(screen[0] + 4, "Channel Status", 14); - line_count = 1; -} - -void display_status_channel(int channel, const char *type, const char *state) -{ - char line[MAX_DISPLAY_WIDTH]; - - /* add empty line after previous channel+subscriber */ - if (line_count > 1 && line_count < MAX_HEIGHT_STATUS) - line_count++; - - if (line_count == MAX_HEIGHT_STATUS) - return; - - if (type) - snprintf(line, sizeof(line), "Channel: %d Type: %s State: %s", channel, type, state); - else - snprintf(line, sizeof(line), "Channel: %d State: %s", channel, state); - line[sizeof(line) - 1] = '\0'; - strncpy(screen[line_count++], line, strlen(line)); -} - -void display_status_subscriber(const char *number, const char *state) -{ - char line[MAX_DISPLAY_WIDTH]; - - if (line_count == MAX_HEIGHT_STATUS) - return; - - if (state) - snprintf(line, sizeof(line), " Subscriber: %s State: %s", number, state); - else - snprintf(line, sizeof(line), " Subscriber: %s", number); - line[sizeof(line) - 1] = '\0'; - strncpy(screen[line_count++], line, strlen(line)); -} - -void display_status_end(void) -{ - if (line_count < MAX_HEIGHT_STATUS) { - memset(screen[line_count], '-', sizeof(screen[line_count])); - line_count++; - } - /* if last total lines exceed current line count, keep it, so removed lines are overwritten with spaces */ - if (line_count > lines_total) - lines_total = line_count; - if (status_on) - print_status(1); - /* set new total lines */ - lines_total = line_count; -} - - diff --git a/src/common/display_wave.c b/src/common/display_wave.c index b88080b..b4005f9 100644 --- a/src/common/display_wave.c +++ b/src/common/display_wave.c @@ -24,7 +24,7 @@ #include #include #include "../libsample/sample.h" -#include "sender.h" +#include "../libmobile/sender.h" #define HEIGHT 11 diff --git a/src/common/main_mobile.c b/src/common/main_mobile.c deleted file mode 100644 index bb83cf8..0000000 --- a/src/common/main_mobile.c +++ /dev/null @@ -1,688 +0,0 @@ -/* Common part for main.c of each base station type - * - * (C) 2016 by Andreas Eversberg - * 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 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../libsample/sample.h" -#include "main_mobile.h" -#include "debug.h" -#include "sender.h" -#include "../libtimer/timer.h" -#include "call.h" -#include "../libmncc/mncc_console.h" -#include "../libmncc/mncc_sock.h" -#include "../libmncc/mncc_cross.h" -#ifdef HAVE_SDR -#include "../libsdr/sdr.h" -#include "../libsdr/sdr_config.h" -#endif - -static int got_init = 0; - -/* common mobile settings */ -int num_kanal = 0; -int kanal[MAX_SENDER]; -int num_audiodev = 0; -const char *audiodev[MAX_SENDER] = { "hw:0,0" }; -int use_sdr = 0; -static const char *call_audiodev = ""; -int samplerate = 48000; -static int call_samplerate = 48000; -int interval = 1; -int latency = 50; -int uses_emphasis = 1; -int do_pre_emphasis = 0; -int do_de_emphasis = 0; -double rx_gain = 1.0; -static int echo_test = 0; -static int use_mncc_sock = 0; -static int use_mncc_cross = 0; -const char *mncc_name = ""; -static int send_patterns = 1; -static int release_on_disconnect = 1; -int loopback = 0; -int rt_prio = 0; -const char *write_tx_wave = NULL; -const char *write_rx_wave = NULL; -const char *read_tx_wave = NULL; -const char *read_rx_wave = NULL; - -void main_mobile_init(void) -{ - got_init = 1; -#ifdef HAVE_SDR - sdr_config_init(); -#endif -} - -void main_mobile_print_help(const char *arg0, const char *ext_usage) -{ - printf("Usage: %s -k %s[options] [station-id]\n", arg0, ext_usage); - printf("\nGlobal options:\n"); - /* - - */ - printf(" -h --help\n"); - printf(" This help\n"); - printf(" -v --verbose | ,[,[,...]] | list\n"); - printf(" Use 'list' to get a list of all levels and categories\n"); - printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel); - printf(" Verbose level+category: level digit followed by one or more categories\n"); - printf(" -> If no category is specified, all categories are selected\n"); - printf(" -k --kanal \n"); - printf(" -k --channel \n"); - printf(" Channel (German = Kanal) number of \"Sender\" (German = Transceiver)\n"); - printf(" -a --audio-device hw:,\n"); - printf(" Sound card and device number (default = '%s')\n", audiodev[0]); - printf(" Don't set it for SDR!\n"); - printf(" -s --samplerate \n"); - printf(" Sample rate of sound device (default = '%d')\n", samplerate); - printf(" -i --interval 1..25\n"); - printf(" Interval of processing loop in ms (default = '%d' ms)\n", interval); - printf(" Use 25 to drastically reduce CPU usage. In case of buffer underrun,\n"); - printf(" increase latency accordingly.\n"); - printf(" -b --buffer \n"); - printf(" How many milliseconds are processed in advance (default = '%d')\n", latency); - if (uses_emphasis) { - printf(" -p --pre-emphasis\n"); - printf(" Enable pre-emphasis, if you directly connect to the oscillator of the\n"); - printf(" transmitter. (No pre-emphasis done by the transmitter.)\n"); - printf(" -d --de-emphasis\n"); - printf(" Enable de-emphasis, if you directly connect to the discriminator of\n"); - printf(" the receiver. (No de-emphasis done by the receiver.)\n"); - } - printf(" -g --rx-gain \n"); - printf(" Raise receiver RX level by given gain in dB. This is useful if input\n"); - printf(" level of the sound device is too low, even after setting maximum level\n"); - printf(" with the mixer settings. (Works with sound card only.)\n"); - printf(" -e --echo-test\n"); - printf(" Use echo test, to send back audio from mobile phone's microphone to\n"); - printf(" the speaker. (German: 'Blasprobe').\n"); - printf(" -c --call-device hw:,\n"); - printf(" Sound card and device number for headset (default = '%s')\n", call_audiodev); - printf(" --call-samplerate \n"); - printf(" Sample rate of sound device for headset (default = '%d')\n", call_samplerate); - printf(" -x --mncc-cross\n"); - printf(" Enable built-in call forwarding between mobiles. Be sure to have\n"); - printf(" at least one control channel and two voice channels. Alternatively\n"); - printf(" use one combined control+voice channel and one voice channels.\n"); - printf(" -m --mncc-sock\n"); - printf(" Disable built-in call contol and offer socket (to LCR)\n"); - printf(" --mncc-name \n"); - printf(" '/tmp/bsc_mncc' is used by default, give name to change socket to\n"); - printf(" '/tmp/bsc_mncc_'. (Useful to run multiple networks.)\n"); - printf(" -t --tones 0 | 1\n"); - printf(" Connect call on setup/release to provide classic tones towards fixed\n"); - printf(" network (default = '%d')\n", send_patterns); - printf(" -l --loopback \n"); - printf(" Loopback test: 1 = internal | 2 = external | 3 = echo\n"); - printf(" -r --realtime \n"); - printf(" Set prio: 0 to diable, 99 for maximum (default = %d)\n", rt_prio); - printf(" --write-rx-wave \n"); - printf(" Write received audio to given wave file.\n"); - printf(" --write-tx-wave \n"); - printf(" Write transmitted audio to given wave file.\n"); - printf(" --read-rx-wave \n"); - printf(" Replace received audio by given wave file.\n"); - printf(" --read-tx-wave \n"); - printf(" Replace transmitted audio by given wave file.\n"); -#ifdef HAVE_SDR - sdr_config_print_help(); -#endif - printf("\nNetwork specific options:\n"); -} - -void main_mobile_print_hotkeys(void) -{ - printf("\n"); - printf("Press digits '0'..'9' and then 'd' key to dial towards mobile station.\n"); - printf("Press 'h' key to hangup.\n"); - printf("Press 'w' key to toggle display of RX wave form.\n"); - printf("Press 'c' key to toggle display of channel status.\n"); - printf("Press 'm' key to toggle display of measurement value.\n"); -#ifdef HAVE_SDR - sdr_config_print_hotkeys(); -#endif -} - -#define OPT_CHANNEL 1000 -#define OPT_WRITE_RX_WAVE 1001 -#define OPT_WRITE_TX_WAVE 1002 -#define OPT_READ_RX_WAVE 1003 -#define OPT_READ_TX_WAVE 1004 -#define OPT_CALL_SAMPLERATE 1005 -#define OPT_MNCC_NAME 1006 - -static struct option main_mobile_long_options[] = { - {"help", 0, 0, 'h'}, - {"debug", 1, 0, 'v'}, - {"kanal", 1, 0, 'k'}, - {"channel", 1, 0, OPT_CHANNEL}, - {"audio-device", 1, 0, 'a'}, - {"samplerate", 1, 0, 's'}, - {"interval", 1, 0, 'i'}, - {"buffer", 1, 0, 'b'}, - {"pre-emphasis", 0, 0, 'p'}, - {"de-emphasis", 0, 0, 'd'}, - {"rx-gain", 1, 0, 'g'}, - {"echo-test", 0, 0, 'e'}, - {"mncc-cross", 0, 0, 'x'}, - {"mncc-sock", 0, 0, 'm'}, - {"mncc-name", 1, 0, OPT_MNCC_NAME}, - {"call-device", 1, 0, 'c'}, - {"call-samplerate", 1, 0, OPT_CALL_SAMPLERATE}, - {"tones", 0, 0, 't'}, - {"loopback", 1, 0, 'l'}, - {"realtime", 1, 0, 'r'}, - {"write-rx-wave", 1, 0, OPT_WRITE_RX_WAVE}, - {"write-tx-wave", 1, 0, OPT_WRITE_TX_WAVE}, - {"read-rx-wave", 1, 0, OPT_READ_RX_WAVE}, - {"read-tx-wave", 1, 0, OPT_READ_TX_WAVE}, - {0, 0, 0, 0} -}; - -static const char *main_mobile_optstring = "hv:k:a:s:i:b:pdg:exmc:t:l:r:"; - -struct option *long_options; -char *optstring; - -static void check_duplicate_option(int num, struct option *option) -{ - int i; - - for (i = 0; i < num; i++) { - if (long_options[i].val == option->val) { - fprintf(stderr, "Duplicate option %d. Please fix!\n", option->val); - abort(); - } - } -} - -void main_mobile_set_options(const char *optstring_special, struct option *long_options_special) -{ - int i = 0, j; - - long_options = calloc(sizeof(*long_options), 256); - for (j = 0; main_mobile_long_options[j].name; i++, j++) { - check_duplicate_option(i, &main_mobile_long_options[j]); - memcpy(&long_options[i], &main_mobile_long_options[j], sizeof(*long_options)); - } -#ifdef HAVE_SDR - for (j = 0; sdr_config_long_options[j].name; i++, j++) { - check_duplicate_option(i, &sdr_config_long_options[j]); - memcpy(&long_options[i], &sdr_config_long_options[j], sizeof(*long_options)); - } -#endif - for (; long_options_special->name; i++) { - check_duplicate_option(i, long_options_special); - memcpy(&long_options[i], long_options_special++, sizeof(*long_options)); - } - - optstring = calloc(256, 2); - strcpy(optstring, main_mobile_optstring); -#ifdef HAVE_SDR - strcat(optstring, sdr_config_optstring); -#endif - strcat(optstring, optstring_special); -} - -void print_help(const char *arg0); - -void main_mobile_opt_switch(int c, char *arg0, int *skip_args) -{ - double gain_db; -#ifdef HAVE_SDR - int rc; -#endif - - switch (c) { - case 'h': - print_help(arg0); - exit(0); - case 'v': - if (!strcasecmp(optarg, "list")) { - debug_list_cat(); - exit(0); - } - if (parse_debug_opt(optarg)) { - fprintf(stderr, "Failed to parse debug option, please use -h for help.\n"); - exit(0); - } - *skip_args += 2; - break; - case 'k': - case OPT_CHANNEL: - OPT_ARRAY(num_kanal, kanal, atoi(optarg)) - *skip_args += 2; - break; - case 'a': - OPT_ARRAY(num_audiodev, audiodev, strdup(optarg)) - *skip_args += 2; - break; - case 's': - samplerate = atoi(optarg); - *skip_args += 2; - break; - case 'i': - interval = atoi(optarg); - *skip_args += 2; - if (interval < 1) - interval = 1; - if (interval > 25) - interval = 25; - break; - case 'b': - latency = atoi(optarg); - *skip_args += 2; - break; - case 'p': - if (!uses_emphasis) { - no_emph: - fprintf(stderr, "This network does not use emphasis, please do not enable pre- or de-emphasis! Disable emphasis on transceiver, if possible.\n"); - exit(0); - } - do_pre_emphasis = 1; - *skip_args += 1; - break; - case 'd': - if (!uses_emphasis) - goto no_emph; - do_de_emphasis = 1; - *skip_args += 1; - break; - case 'g': - gain_db = atof(optarg); - if (gain_db < 0.0) { - fprintf(stderr, "Given gain is below 0. To reduce RX signal, use sound card's mixer (or resistor net)!\n"); - exit(0); - } - rx_gain = pow(10, gain_db / 20.0); - *skip_args += 2; - break; - case 'e': - echo_test = 1; - *skip_args += 1; - break; - case 'x': - use_mncc_cross = 1; - *skip_args += 1; - break; - case 'm': - use_mncc_sock = 1; - *skip_args += 1; - break; - case OPT_MNCC_NAME: - mncc_name = strdup(optarg); - *skip_args += 2; - break; - case 'c': - call_audiodev = strdup(optarg); - *skip_args += 2; - break; - case OPT_CALL_SAMPLERATE: - call_samplerate = atoi(optarg); - *skip_args += 2; - break; - case 't': - send_patterns = atoi(optarg); - *skip_args += 2; - break; - case 'l': - loopback = atoi(optarg); - *skip_args += 2; - break; - case 'r': - rt_prio = atoi(optarg); - *skip_args += 2; - break; - case OPT_WRITE_RX_WAVE: - write_rx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_WRITE_TX_WAVE: - write_tx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_READ_RX_WAVE: - read_rx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_READ_TX_WAVE: - read_tx_wave = strdup(optarg); - *skip_args += 2; - break; - default: -#ifdef HAVE_SDR - rc = sdr_config_opt_switch(c, skip_args); - if (rc < 0) - exit (0); - -#endif - break; - } -} - -/* global variable to quit main loop */ -int quit = 0; - -void sighandler(int sigset) -{ - if (sigset == SIGHUP) - return; - if (sigset == SIGPIPE) - return; - - clear_console_text(); - printf("Signal received: %d\n", sigset); - - quit = 1; -} - -static int get_char() -{ - struct timeval tv = {0, 0}; - fd_set fds; - char c = 0; - int __attribute__((__unused__)) rc; - - FD_ZERO(&fds); - FD_SET(0, &fds); - select(0+1, &fds, NULL, NULL, &tv); - if (FD_ISSET(0, &fds)) { - rc = read(0, &c, 1); - return c; - } else - return -1; -} - -/* Loop through all transceiver instances of one network. */ -void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), const char *station_id, int station_id_digits) -{ - int latspl; - sender_t *sender; - double last_time_call = 0, begin_time, now, sleep; - struct termios term, term_orig; - int c; - int rc; - - if (!got_init) { - fprintf(stderr, "main_mobile_init was not called, please fix!\n"); - abort(); - } - - /* latency of send buffer in samples */ - latspl = samplerate * latency / 1000; - - /* check MNCC support */ - if (use_mncc_cross && num_kanal == 1) { - fprintf(stderr, "You selected built-in call forwarding, but only channel is used. Does this makes sense?\n"); - return; - } - if (use_mncc_sock && use_mncc_cross) { - fprintf(stderr, "You selected MNCC socket interface and built-in call forwarding, but only one can be selected.\n"); - return; - } - if (echo_test && call_audiodev[0]) { - fprintf(stderr, "You selected call device (headset) and echo test, but only one can be selected.\n"); - return; - } - if (use_mncc_sock && call_audiodev[0]) { - fprintf(stderr, "You selected MNCC socket interface, but it cannot be used with call device (headset).\n"); - return; - } - if (use_mncc_cross && call_audiodev[0]) { - fprintf(stderr, "You selected built-in call forwarding, but it cannot be used with call device (headset).\n"); - return; - } - if (use_mncc_sock && echo_test) { - fprintf(stderr, "You selected MNCC socket interface, but it cannot be used with echo test.\n"); - return; - } - if (use_mncc_cross && echo_test) { - fprintf(stderr, "You selected built-in call forwarding, but it cannot be used with echo test.\n"); - return; - } - - /* init mncc */ - if (use_mncc_sock) { - char mncc_sock_name[64]; - if (mncc_name[0]) { - snprintf(mncc_sock_name, sizeof(mncc_sock_name), "/tmp/bsc_mncc_%s", mncc_name); - mncc_sock_name[sizeof(mncc_sock_name) - 1] = '\0'; - } else - strcpy(mncc_sock_name, "/tmp/bsc_mncc"); - rc = mncc_sock_init(mncc_sock_name); - if (rc < 0) { - fprintf(stderr, "Failed to setup MNCC socket. Quitting!\n"); - return; - } - } else if (use_mncc_cross) { - rc = mncc_cross_init(); - if (rc < 0) { - fprintf(stderr, "Failed to setup MNCC crossing process. Quitting!\n"); - return; - } - } else { - console_init(station_id, call_audiodev, call_samplerate, latency, station_id_digits, loopback, echo_test); - } - - /* init call control instance */ - rc = call_init((use_mncc_sock) ? send_patterns : 0, release_on_disconnect); - if (rc < 0) { - fprintf(stderr, "Failed to create call control instance. Quitting!\n"); - return; - } - -#ifdef HAVE_SDR - rc = sdr_configure(samplerate); - if (rc < 0) - return; -#endif - - /* open audio */ - if (sender_open_audio(latspl)) - return; - if (console_open_audio(latspl)) - return; - - /* real time priority */ - if (rt_prio > 0) { - struct sched_param schedp; - int rc; - - memset(&schedp, 0, sizeof(schedp)); - schedp.sched_priority = rt_prio; - rc = sched_setscheduler(0, SCHED_RR, &schedp); - if (rc) - fprintf(stderr, "Error setting SCHED_RR with prio %d\n", rt_prio); - } - - /* prepare terminal */ - tcgetattr(0, &term_orig); - term = term_orig; - term.c_lflag &= ~(ISIG|ICANON|ECHO); - term.c_cc[VMIN]=1; - term.c_cc[VTIME]=2; - tcsetattr(0, TCSANOW, &term); - - /* catch signals */ - signal(SIGINT, sighandler); - signal(SIGHUP, sighandler); - signal(SIGTERM, sighandler); - signal(SIGPIPE, sighandler); - - /* start streaming */ - if (sender_start_audio()) - *quit = 1; - if (console_start_audio()) - *quit = 1; - - while(!(*quit)) { - begin_time = get_time(); - - /* process sound of all transceivers */ - for (sender = sender_head; sender; sender = sender->next) { - /* do not process audio for an audio slave, since it is done by audio master */ - if (sender->master) /* if master is set, we are an audio slave */ - continue; - process_sender_audio(sender, quit, latspl); - } - - /* process timers */ - process_timer(); - - /* process audio for mncc call instances */ - now = get_time(); - if (now - last_time_call >= 0.1) - last_time_call = now; - if (now - last_time_call >= 0.020) { - last_time_call += 0.020; - /* call clock every 20ms */ - call_clock(); - } - -next_char: - c = get_char(); - switch (c) { - case 3: - /* quit */ - clear_console_text(); - printf("CTRL+c received, quitting!\n"); - *quit = 1; - goto next_char; - case 'w': - /* toggle wave display */ - display_status_on(0); - display_measurements_on(0); -#ifdef HAVE_SDR - display_iq_on(0); - display_spectrum_on(0); -#endif - display_wave_on(-1); - goto next_char; - case 'c': - /* toggle call state display */ - display_wave_on(0); - display_measurements_on(0); -#ifdef HAVE_SDR - display_iq_on(0); - display_spectrum_on(0); -#endif - display_status_on(-1); - goto next_char; - case 'm': - /* toggle measurements display */ - display_wave_on(0); - display_status_on(0); -#ifdef HAVE_SDR - display_iq_on(0); - display_spectrum_on(0); -#endif - display_measurements_on(-1); - goto next_char; -#ifdef HAVE_SDR - case 'q': - /* toggle IQ display */ - display_wave_on(0); - display_status_on(0); - display_measurements_on(0); - display_spectrum_on(0); - display_iq_on(-1); - goto next_char; - case 's': - /* toggle spectrum display */ - display_wave_on(0); - display_status_on(0); - display_measurements_on(0); - display_iq_on(0); - display_spectrum_on(-1); - goto next_char; -#endif - case 'i': - /* dump info */ - dump_info(); - goto next_char; - } - - /* process call control */ - if (use_mncc_sock) - mncc_sock_handle(); - else if (use_mncc_cross) - mncc_cross_handle(); - else - process_console(c); - - if (myhandler) - myhandler(); - - display_measurements((double)interval / 1000.0); - - now = get_time(); - - /* sleep interval */ - sleep = ((double)interval / 1000.0) - (now - begin_time); - if (sleep > 0) - usleep(sleep * 1000000.0); - -// now = get_time(); -// printf("duration =%.6f\n", now - begin_time); - } - - /* reset signals */ - signal(SIGINT, SIG_DFL); - signal(SIGHUP, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGPIPE, SIG_DFL); - - /* get rid of last entry */ - clear_console_text(); - - /* reset terminal */ - tcsetattr(0, TCSANOW, &term_orig); - - /* reset real time prio */ - if (rt_prio > 0) { - struct sched_param schedp; - - memset(&schedp, 0, sizeof(schedp)); - schedp.sched_priority = 0; - sched_setscheduler(0, SCHED_OTHER, &schedp); - } - - /* cleanup call control */ - if (!use_mncc_sock && !use_mncc_cross) - console_cleanup(); - - /* close mncc socket */ - if (use_mncc_sock) - mncc_sock_exit(); - - /* close mncc forwarding */ - if (use_mncc_cross) - mncc_cross_exit(); -} - diff --git a/src/common/main_mobile.h b/src/common/main_mobile.h deleted file mode 100644 index e958f2c..0000000 --- a/src/common/main_mobile.h +++ /dev/null @@ -1,45 +0,0 @@ - -extern int num_kanal; -extern int kanal[]; -extern int swap_links; -extern int num_audiodev; -extern const char *audiodev[]; -extern int use_sdr; -extern int samplerate; -extern int interval; -extern int latency; -extern int uses_emphasis; -extern int do_pre_emphasis; -extern int do_de_emphasis; -extern double rx_gain; -extern int loopback; -extern int rt_prio; -extern const char *write_rx_wave; -extern const char *write_tx_wave; -extern const char *read_rx_wave; -extern const char *read_tx_wave; - -void main_mobile_init(void); -void main_mobile_print_help(const char *arg0, const char *ext_usage); -void main_mobile_print_hotkeys(void); -extern struct option *long_options; -extern char *optstring; -void main_mobile_set_options(const char *optstring_special, struct option *long_options_special); -void main_mobile_opt_switch(int c, char *arg0, int *skip_args); - -#define OPT_ARRAY(num_name, name, value) \ -{ \ - if (num_name == MAX_SENDER) { \ - fprintf(stderr, "Too many channels defined!\n"); \ - exit(0); \ - } \ - name[num_name++] = value; \ -} - -extern int quit; -void sighandler(int sigset); - -void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), const char *station_id, int station_id_digits); - -void dump_info(void); - diff --git a/src/common/sender.c b/src/common/sender.c deleted file mode 100644 index ff14e93..0000000 --- a/src/common/sender.c +++ /dev/null @@ -1,449 +0,0 @@ -/* Common transceiver functions - * - * (C) 2016 by Andreas Eversberg - * 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 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 . - */ - -#define CHAN sender->kanal - -#include -#include -#include -#include -#include -#include "../libsample/sample.h" -#include "debug.h" -#include "sender.h" -#include "../libtimer/timer.h" - -/* debug time consumption of audio processing */ -//#define DEBUG_TIME_CONSUMPTION - -sender_t *sender_head = NULL; -static sender_t **sender_tailp = &sender_head; -int cant_recover = 0; - -/* Init transceiver instance and link to list of transceivers. */ -int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback, enum paging_signal paging_signal) -{ - sender_t *master, *slave; - int rc = 0; - - sender->kanal = kanal; - sender->sendefrequenz = sendefrequenz; - sender->empfangsfrequenz = (loopback) ? sendefrequenz : empfangsfrequenz; - strncpy(sender->audiodev, audiodev, sizeof(sender->audiodev) - 1); - sender->samplerate = samplerate; - sender->rx_gain = rx_gain; - sender->pre_emphasis = pre_emphasis; - sender->de_emphasis = de_emphasis; - sender->loopback = loopback; - sender->paging_signal = paging_signal; - sender->write_rx_wave = write_rx_wave; - sender->write_tx_wave = write_tx_wave; - sender->read_rx_wave = read_rx_wave; - sender->read_tx_wave = read_tx_wave; - - /* no gain with SDR */ - if (use_sdr) - sender->rx_gain = 1.0; - - PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Creating 'Sender' instance\n"); - - /* if we find a channel that uses the same device as we do, - * we will link us as slave to this master channel. then we - * receive and send audio via second channel of the device - * of the master channel. - */ - for (master = sender_head; master; master = master->next) { - if (master->kanal == kanal) { - PDEBUG(DSENDER, DEBUG_ERROR, "Channel %d may not be defined for multiple transceivers!\n", kanal); - rc = -EIO; - goto error; - } - if (abs(master->kanal - kanal) == 1) { - PDEBUG(DSENDER, DEBUG_NOTICE, "------------------------------------------------------------------------\n"); - PDEBUG(DSENDER, DEBUG_NOTICE, "NOTE: Channel %d is next to channel %d. This will cause interferences.\n", kanal, master->kanal); - PDEBUG(DSENDER, DEBUG_NOTICE, "Please use at least one channel distance to avoid that.\n"); - PDEBUG(DSENDER, DEBUG_NOTICE, "------------------------------------------------------------------------\n"); - } - if (!strcmp(master->audiodev, audiodev)) - break; - } - if (master) { - if (master->paging_signal != PAGING_SIGNAL_NONE && !use_sdr) { - PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because its second audio channel is used for paging signal! Use different audio device.\n", master->kanal); - rc = -EBUSY; - goto error; - } - if (paging_signal != PAGING_SIGNAL_NONE && !use_sdr) { - PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because we need a second audio channel for paging signal! Use different audio device.\n", master->kanal); - rc = -EBUSY; - goto error; - } - /* link us to a master */ - sender->master = master; - /* link master (or last slave) to us */ - for (slave = master; ; slave = slave->slave) { - if (!slave->slave) - break; - } - slave->slave = sender; - } else { - /* link audio device */ -#ifdef HAVE_SDR - if (use_sdr) { - sender->audio_open = sdr_open; - sender->audio_start = sdr_start; - sender->audio_close = sdr_close; - sender->audio_read = sdr_read; - sender->audio_write = sdr_write; - sender->audio_get_tosend = sdr_get_tosend; - } else -#endif - { - sender->audio_open = sound_open; - sender->audio_start = sound_start; - sender->audio_close = sound_close; - sender->audio_read = sound_read; - sender->audio_write = sound_write; - sender->audio_get_tosend = sound_get_tosend; - } - } - - rc = init_samplerate(&sender->srstate, 8000.0, (double)samplerate, 3300.0); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n"); - goto error; - } - - rc = jitter_create(&sender->dejitter, samplerate / 5); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init audio buffer!\n"); - goto error; - } - - rc = init_emphasis(&sender->estate, samplerate, CUT_OFF_EMPHASIS_DEFAULT); - if (rc < 0) - goto error; - - *sender_tailp = sender; - sender_tailp = &sender->next; - - display_wave_init(sender, samplerate); - display_measurements_init(sender, samplerate); - - return 0; -error: - sender_destroy(sender); - - return rc; -} - -int sender_open_audio(int latspl) -{ - sender_t *master, *inst; - int channels; - int i; - int rc; - - for (master = sender_head; master; master = master->next) { - /* skip audio slaves */ - if (master->master) - continue; - - /* get list of frequencies */ - channels = 0; - for (inst = master; inst; inst = inst->slave) { - channels++; - } - double tx_f[channels], rx_f[channels], paging_frequency = 0.0; - for (i = 0, inst = master; inst; i++, inst = inst->slave) { - tx_f[i] = inst->sendefrequenz; - rx_f[i] = inst->empfangsfrequenz; - if (inst->ruffrequenz) - paging_frequency = inst->ruffrequenz; - } - - if (master->write_rx_wave) { - rc = wave_create_record(&master->wave_rx_rec, master->write_rx_wave, master->samplerate, channels, master->max_deviation); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); - return rc; - } - } - if (master->write_tx_wave) { - rc = wave_create_record(&master->wave_tx_rec, master->write_tx_wave, master->samplerate, channels, master->max_deviation); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); - return rc; - } - } - if (master->read_rx_wave) { - rc = wave_create_playback(&master->wave_rx_play, master->read_rx_wave, master->samplerate, channels, master->max_deviation); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); - return rc; - } - } - if (master->read_tx_wave) { - rc = wave_create_playback(&master->wave_tx_play, master->read_tx_wave, master->samplerate, channels, master->max_deviation); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); - return rc; - } - } - - /* open device */ - master->audio = master->audio_open(master->audiodev, tx_f, rx_f, channels, paging_frequency, master->samplerate, latspl, master->max_deviation, master->max_modulation); - if (!master->audio) { - PDEBUG(DSENDER, DEBUG_ERROR, "No audio device!\n"); - return -EIO; - } - } - - return 0; -} - -int sender_start_audio(void) -{ - sender_t *master; - int rc = 0; - - for (master = sender_head; master; master = master->next) { - /* skip audio slaves */ - if (master->master) - continue; - - rc = master->audio_start(master->audio); - if (rc) - break; - } - - return rc; -} - -/* Destroy transceiver instance and unlink from list. */ -void sender_destroy(sender_t *sender) -{ - PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Destroying 'Sender' instance\n"); - - sender_tailp = &sender_head; - while (*sender_tailp) { - if (sender == *sender_tailp) - *sender_tailp = (*sender_tailp)->next; - else - sender_tailp = &((*sender_tailp)->next); - } - - if (sender->audio) { - sender->audio_close(sender->audio); - sender->audio = NULL; - } - - wave_destroy_record(&sender->wave_rx_rec); - wave_destroy_record(&sender->wave_tx_rec); - wave_destroy_playback(&sender->wave_rx_play); - wave_destroy_playback(&sender->wave_tx_play); - - jitter_destroy(&sender->dejitter); -} - -void sender_set_fm(sender_t *sender, double max_deviation, double max_modulation, double dBm0_deviation, double max_display) -{ - sender->max_deviation = max_deviation; - sender->max_modulation = max_modulation; - sender->dBm0_deviation = dBm0_deviation; - sender->max_display = max_display; - - PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Maxium deviation: %.1f kHz, Maximum modulation: %.1f kHz\n", max_deviation / 1000.0, max_modulation / 1000.0); - PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Deviation at dBm0 (audio level): %.1f kHz\n", dBm0_deviation / 1000.0); -} - -static void gain_samples(sample_t *samples, int length, double gain) -{ - int i; - - for (i = 0; i < length; i++) - *samples++ *= gain; -} - -/* Handle audio streaming of one transceiver. */ -void process_sender_audio(sender_t *sender, int *quit, int latspl) -{ - sender_t *inst; - int rc, count; - int num_chan, i; -#ifdef DEBUG_TIME_CONSUMPTION - static double t1, t2, t3, t4, t5, d1 = 0, d2 = 0, d3 = 0, d4 = 0, s = 0; -#endif - - /* count instances for audio channel */ - for (num_chan = 0, inst = sender; inst; num_chan++, inst = inst->slave); - sample_t buff[num_chan][latspl], *samples[num_chan]; - uint8_t pbuff[num_chan][latspl], *power[num_chan]; - enum paging_signal paging_signal[num_chan]; - int on[num_chan]; - double rf_level_db[num_chan]; - for (i = 0; i < num_chan; i++) { - samples[i] = buff[i]; - power[i] = pbuff[i]; - } - -#ifdef DEBUG_TIME_CONSUMPTION - t1 = get_time(); -#endif - count = sender->audio_get_tosend(sender->audio, latspl); - if (count < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); - if (count == -EPIPE) { - if (cant_recover) { -cant_recover: - PDEBUG(DSENDER, DEBUG_ERROR, "Cannot recover due to measurements, quitting!\n"); - *quit = 1; - return; - } - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); - } - return; - } -#ifdef DEBUG_TIME_CONSUMPTION - t2 = get_time(); -#endif - if (count > 0) { - /* limit to our buffer */ - if (count > latspl) - count = latspl; - /* loop through all channels */ - for (i = 0, inst = sender; inst; i++, inst = inst->slave) { - /* load TX data from audio loop or from sender instance */ - if (inst->loopback == 3) - jitter_load(&inst->dejitter, samples[i], count); - else - sender_send(inst, samples[i], power[i], count); - /* internal loopback: loop back TX audio to RX */ - if (inst->loopback == 1) { - display_wave(inst, samples[i], count, inst->max_display); - sender_receive(inst, samples[i], count, 0.0); - } - /* do pre emphasis towards radio */ - if (inst->pre_emphasis) - pre_emphasis(&inst->estate, samples[i], count); - /* normal level to frequency deviation of dBm0 */ - gain_samples(samples[i], count, inst->dBm0_deviation); - /* set paging signal */ - paging_signal[i] = inst->paging_signal; - on[i] = inst->paging_on; - } - -#ifdef DEBUG_TIME_CONSUMPTION - t2 = get_time(); -#endif - if (sender->wave_tx_rec.fp) - wave_write(&sender->wave_tx_rec, samples, count); - if (sender->wave_tx_play.fp) - wave_read(&sender->wave_tx_play, samples, count); - - rc = sender->audio_write(sender->audio, samples, power, count, paging_signal, on, num_chan); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc); - if (rc == -EPIPE) { - if (cant_recover) - goto cant_recover; - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); - } - return; - } - } -#ifdef DEBUG_TIME_CONSUMPTION - t3 = get_time(); -#endif - - count = sender->audio_read(sender->audio, samples, latspl, num_chan, rf_level_db); - if (count < 0) { - /* special case when audio_read wants us to quit */ - if (count == -EPERM) { - *quit = 1; - return; - } - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from audio device (rc = %d)!\n", count); - if (count == -EPIPE) { - if (cant_recover) - goto cant_recover; - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); - } - return; - } -#ifdef DEBUG_TIME_CONSUMPTION - t4 = get_time(); -#endif - if (count) { - if (sender->wave_rx_rec.fp) - wave_write(&sender->wave_rx_rec, samples, count); - if (sender->wave_rx_play.fp) - wave_read(&sender->wave_rx_play, samples, count); - - /* loop through all channels */ - for (i = 0, inst = sender; inst; i++, inst = inst->slave) { - /* frequency deviation of dBm0 to normal level */ - gain_samples(samples[i], count, 1.0 / inst->dBm0_deviation); - /* rx gain */ - if (inst->rx_gain != 1.0) - gain_samples(samples[i], count, inst->rx_gain); - /* do filter and de-emphasis from radio receive audio, process echo test */ - if (inst->de_emphasis) { - dc_filter(&inst->estate, samples[i], count); - de_emphasis(&inst->estate, samples[i], count); - } - if (inst->loopback != 1) { - display_wave(inst, samples[i], count, inst->max_display); - sender_receive(inst, samples[i], count, rf_level_db[i]); - } - if (inst->loopback == 3) - jitter_save(&inst->dejitter, samples[i], count); - } - } -#ifdef DEBUG_TIME_CONSUMPTION - t5 = get_time(); - d1 += (t2 - t1); - d2 += (t3 - t2); - d3 += (t4 - t3); - d4 += (t5 - t4); - if (get_time() - s >= 1.0) { - printf("duration: %.3f (process TX), %.3f (send TX), %.3f (receive RX), %.3f (process RX)\n", d1, d2, d3, d4); - s = get_time(); - d1 = d2 = d3 = d4 = 0; - } -#endif -} - -void sender_paging(sender_t *sender, int on) -{ - sender->paging_on = on; -} - -sender_t *get_sender_by_empfangsfrequenz(double freq) -{ - sender_t *sender; - - for (sender = sender_head; sender; sender = sender->next) { - if (sender->empfangsfrequenz == freq) - return sender; - } - - return NULL; -} - diff --git a/src/common/sender.h b/src/common/sender.h deleted file mode 100644 index 12a17c9..0000000 --- a/src/common/sender.h +++ /dev/null @@ -1,101 +0,0 @@ -#include "../libsound/sound.h" -#ifdef HAVE_SDR -#include "../libsdr/sdr.h" -#endif -#include "../libwave/wave.h" -#include "../libsamplerate/samplerate.h" -#include "../libjitter/jitter.h" -#include "../libemphasis/emphasis.h" -#include "display.h" - -#define MAX_SENDER 16 - -/* how to send a 'paging' signal (trigger transmitter) */ -enum paging_signal { - PAGING_SIGNAL_NONE = 0, - PAGING_SIGNAL_TONE, - PAGING_SIGNAL_NOTONE, - PAGING_SIGNAL_POSITIVE, - PAGING_SIGNAL_NEGATIVE, -}; - -/* common structure of each transmitter */ -typedef struct sender { - struct sender *next; - struct sender *slave; /* points to 'slave' that uses next channel of audio device */ - struct sender *master; /* if set, the audio device is owned by 'master' */ - - /* system info */ - int kanal; /* channel number */ - double sendefrequenz; /* transmitter frequency */ - double empfangsfrequenz; /* receiver frequency */ - double ruffrequenz; /* special paging frequency used for B-Netz */ - - /* fm levels */ - double max_deviation; /* max frequency deviation */ - double max_modulation; /* max frequency modulated */ - double dBm0_deviation; /* deviation of 1000 Hz reference tone at dBm0 */ - double max_display; /* level of displaying wave form */ - - /* audio */ - void *audio; - char audiodev[64]; /* audio device name (alsa or sdr) */ - void *(*audio_open)(const char *, double *, double *, int, double, int, int, double, double); - int (*audio_start)(void *); - void (*audio_close)(void *); - int (*audio_write)(void *, sample_t **, uint8_t **, int, enum paging_signal *, int *, int); - int (*audio_read)(void *, sample_t **, int, int, double *); - int (*audio_get_tosend)(void *, int); - int samplerate; - samplerate_t srstate; /* sample rate conversion state */ - double rx_gain; /* factor of level to apply on rx samples */ - int pre_emphasis; /* use pre_emhasis, done by sender */ - int de_emphasis; /* use de_emhasis, done by sender */ - emphasis_t estate; /* pre and de emphasis */ - - /* loopback test */ - int loopback; /* 0 = off, 1 = internal, 2 = external */ - - /* record and playback */ - const char *write_rx_wave; /* file name pointers */ - const char *write_tx_wave; - const char *read_rx_wave; - const char *read_tx_wave; - wave_rec_t wave_rx_rec; /* wave recording (from rx) */ - wave_rec_t wave_tx_rec; /* wave recording (from tx) */ - wave_play_t wave_rx_play; /* wave playback (as rx) */ - wave_play_t wave_tx_play; /* wave playback (as tx) */ - - /* audio buffer for audio to send to transmitter (also used as loopback buffer) */ - jitter_t dejitter; - - /* audio buffer for audio to send to caller (20ms = 160 samples @ 8000Hz) */ - sample_t rxbuf[160]; - int rxbuf_pos; /* current fill of buffer */ - - /* paging tone */ - enum paging_signal paging_signal; /* if paging signal is used and how it is performed */ - int paging_on; /* 1 or 0 for on or off */ - - /* display wave */ - dispwav_t dispwav; /* display wave form */ - - /* display measurements */ - dispmeas_t dispmeas; /* display measurements */ -} sender_t; - -/* list of all senders */ -extern sender_t *sender_head; -extern int cant_recover; - -int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback, enum paging_signal paging_signal); -void sender_destroy(sender_t *sender); -void sender_set_fm(sender_t *sender, double max_deviation, double max_modulation, double dBm0_deviation, double max_display); -int sender_open_audio(int latspl); -int sender_start_audio(void); -void process_sender_audio(sender_t *sender, int *quit, int latspl); -void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int count); -void sender_receive(sender_t *sender, sample_t *samples, int count, double rf_level_db); -void sender_paging(sender_t *sender, int on); -sender_t *get_sender_by_empfangsfrequenz(double freq); - diff --git a/src/jtacs/Makefile.am b/src/jtacs/Makefile.am index a920e03..e13fd28 100644 --- a/src/jtacs/Makefile.am +++ b/src/jtacs/Makefile.am @@ -12,10 +12,10 @@ jtacs_SOURCES = \ jtacs_LDADD = \ $(COMMON_LA) \ ../amps/libamps.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/libmncc/mncc_console.c b/src/libmncc/mncc_console.c index 5bfbc9f..273e377 100644 --- a/src/libmncc/mncc_console.c +++ b/src/libmncc/mncc_console.c @@ -32,7 +32,7 @@ #include "mncc.h" #include "mncc_console.h" #include "cause.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libsound/sound.h" static int new_callref = 0; /* toward mobile */ diff --git a/src/libmncc/mncc_cross.c b/src/libmncc/mncc_cross.c index 9609d78..36d3a64 100644 --- a/src/libmncc/mncc_cross.c +++ b/src/libmncc/mncc_cross.c @@ -24,7 +24,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "cause.h" #include "mncc.h" #include "mncc_cross.h" diff --git a/src/libmncc/mncc_sock.c b/src/libmncc/mncc_sock.c index 7f90b11..5343a7e 100644 --- a/src/libmncc/mncc_sock.c +++ b/src/libmncc/mncc_sock.c @@ -28,7 +28,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "cause.h" #include "mncc_sock.h" diff --git a/src/libmobile/Makefile.am b/src/libmobile/Makefile.am new file mode 100644 index 0000000..8b2a0e6 --- /dev/null +++ b/src/libmobile/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) + +noinst_LIBRARIES = libmobile.a + +libmobile_a_SOURCES = \ + sender.c \ + call.c \ + display_status.c \ + main_mobile.c + +if HAVE_SDR +AM_CPPFLAGS += -DHAVE_SDR +endif + diff --git a/src/libmobile/call.c b/src/libmobile/call.c new file mode 100644 index 0000000..a3bce20 --- /dev/null +++ b/src/libmobile/call.c @@ -0,0 +1,796 @@ +/* interface between mobile network/phone implementation and MNCC + * + * (C) 2016 by Andreas Eversberg + * 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 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../libsample/sample.h" +#include "../common/debug.h" +#include "sender.h" +#include "call.h" +#include "../libtimer/timer.h" +#include "../libmncc/mncc.h" +#include "../libmncc/cause.h" + +#define DISC_TIMEOUT 30 + +//#define DEBUG_LEVEL + +#ifdef DEBUG_LEVEL +static double level_of(double *samples, int count) +{ + double level = 0; + int i; + + for (i = 0; i < count; i++) { + if (samples[i] > level) + level = samples[i]; + } + + return level; +} +#endif + +static int send_patterns; /* send patterns towards fixed network */ +static int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */ + +/* stream patterns/announcements */ +int16_t *ringback_spl = NULL; +int ringback_size = 0; +int ringback_max = 0; +int16_t *hangup_spl = NULL; +int hangup_size = 0; +int hangup_max = 0; +int16_t *busy_spl = NULL; +int busy_size = 0; +int busy_max = 0; +int16_t *noanswer_spl = NULL; +int noanswer_size = 0; +int noanswer_max = 0; +int16_t *outoforder_spl = NULL; +int outoforder_size = 0; +int outoforder_max = 0; +int16_t *invalidnumber_spl = NULL; +int invalidnumber_size = 0; +int invalidnumber_max = 0; +int16_t *congestion_spl = NULL; +int congestion_size = 0; +int congestion_max = 0; +int16_t *recall_spl = NULL; +int recall_size = 0; +int recall_max = 0; + +enum audio_pattern { + PATTERN_NONE = 0, + PATTERN_TEST, + PATTERN_RINGBACK, + PATTERN_HANGUP, + PATTERN_BUSY, + PATTERN_NOANSWER, + PATTERN_OUTOFORDER, + PATTERN_INVALIDNUMBER, + PATTERN_CONGESTION, + PATTERN_RECALL, +}; + +static void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern) +{ + *spl = NULL; + *size = 0; + *max = 0; + + switch (pattern) { + case PATTERN_RINGBACK: +no_recall: + *spl = ringback_spl; + *size = ringback_size; + *max = ringback_max; + break; + case PATTERN_HANGUP: + if (!hangup_spl) + goto no_hangup; + *spl = hangup_spl; + *size = hangup_size; + *max = hangup_max; + break; + case PATTERN_BUSY: +no_hangup: +no_noanswer: + *spl = busy_spl; + *size = busy_size; + *max = busy_max; + break; + case PATTERN_NOANSWER: + if (!noanswer_spl) + goto no_noanswer; + *spl = noanswer_spl; + *size = noanswer_size; + *max = noanswer_max; + break; + case PATTERN_OUTOFORDER: + if (!outoforder_spl) + goto no_outoforder; + *spl = outoforder_spl; + *size = outoforder_size; + *max = outoforder_max; + break; + case PATTERN_INVALIDNUMBER: + if (!invalidnumber_spl) + goto no_invalidnumber; + *spl = invalidnumber_spl; + *size = invalidnumber_size; + *max = invalidnumber_max; + break; + case PATTERN_CONGESTION: +no_outoforder: +no_invalidnumber: + *spl = congestion_spl; + *size = congestion_size; + *max = congestion_max; + break; + case PATTERN_RECALL: + if (!recall_spl) + goto no_recall; + *spl = recall_spl; + *size = recall_size; + *max = recall_max; + break; + default: + ; + } +} + +static enum audio_pattern cause2pattern(int cause) +{ + int pattern; + + switch (cause) { + case CAUSE_NORMAL: + pattern = PATTERN_HANGUP; + break; + case CAUSE_BUSY: + pattern = PATTERN_BUSY; + break; + case CAUSE_NOANSWER: + pattern = PATTERN_NOANSWER; + break; + case CAUSE_OUTOFORDER: + pattern = PATTERN_OUTOFORDER; + break; + case CAUSE_INVALNUMBER: + pattern = PATTERN_INVALIDNUMBER; + break; + case CAUSE_NOCHANNEL: + pattern = PATTERN_CONGESTION; + break; + default: + pattern = PATTERN_HANGUP; + } + + return pattern; +} + +enum process_state { + PROCESS_IDLE = 0, /* IDLE */ + PROCESS_SETUP_RO, /* call from radio to MNCC */ + PROCESS_SETUP_RT, /* call from MNCC to radio */ + PROCESS_ALERTING_RO, /* call from radio to MNCC */ + PROCESS_ALERTING_RT, /* call from MNCC to radio */ + PROCESS_CONNECT, + PROCESS_DISCONNECT, +}; + +/* MNCC call instance */ +typedef struct process { + struct process *next; + int callref; + enum process_state state; + int audio_disconnected; /* if not associated with transceiver anymore */ + enum audio_pattern pattern; + int audio_pos; + uint8_t cause; + struct timer timer; +} process_t; + +static process_t *process_head = NULL; + +static void process_timeout(struct timer *timer); + +static process_t *create_process(int callref, enum process_state state) +{ + process_t *process; + + process = calloc(sizeof(*process), 1); + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "No memory!\n"); + abort(); + } + timer_init(&process->timer, process_timeout, process); + process->next = process_head; + process_head = process; + + process->callref = callref; + process->state = state; + + return process; +} + +static void destroy_process(int callref) +{ + process_t *process = process_head; + process_t **process_p = &process_head; + + while (process) { + if (process->callref == callref) { + *process_p = process->next; + timer_exit(&process->timer); + free(process); + return; + } + process_p = &process->next; + process = process->next; + } + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); +} + +static process_t *get_process(int callref) +{ + process_t *process = process_head; + + while (process) { + if (process->callref == callref) + return process; + process = process->next; + } + return NULL; +} + +static void new_state_process(int callref, enum process_state state) +{ + process_t *process = get_process(callref); + + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + return; + } + process->state = state; +} + +static void set_pattern_process(int callref, enum audio_pattern pattern) +{ + process_t *process = get_process(callref); + + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + return; + } + process->pattern = pattern; + process->audio_pos = 0; +} + +/* disconnect audio, now send audio directly from pattern/announcement, not from transceiver */ +static void disconnect_process(int callref, int cause) +{ + process_t *process = get_process(callref); + + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + return; + } + process->pattern = cause2pattern(cause); + process->audio_disconnected = 1; + process->audio_pos = 0; + process->cause = cause; + timer_start(&process->timer, DISC_TIMEOUT); +} + +static void get_process_patterns(process_t *process, int16_t *samples, int length) +{ + const int16_t *spl; + int size, max, pos; + + get_pattern(&spl, &size, &max, process->pattern); + + /* stream sample */ + pos = process->audio_pos; + while(length--) { + if (pos >= size) + *samples++ = 0; + else + *samples++ = spl[pos] >> 1; + if (++pos == max) + pos = 0; + } + process->audio_pos = pos; +} + +static void process_timeout(struct timer *timer) +{ + process_t *process = (process_t *)timer->priv; + + { + /* announcement timeout */ + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + + if (process->state == PROCESS_DISCONNECT) { + PDEBUG(DCALL, DEBUG_INFO, "Call released toward mobile network (after timeout)\n"); + call_down_release(process->callref, process->cause); + } + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_REL_IND; + mncc->callref = process->callref; + mncc->fields |= MNCC_F_CAUSE; + mncc->cause.location = LOCATION_PRIVATE_LOCAL; + mncc->cause.value = process->cause; + + destroy_process(process->callref); + PDEBUG(DCALL, DEBUG_INFO, "Releasing MNCC call towards fixed network (after timeout)\n"); + mncc_up(buf, sizeof(struct gsm_mncc)); + } +} + +int call_init(int _send_patterns, int _release_on_disconnect) +{ + send_patterns = _send_patterns; + release_on_disconnect = _release_on_disconnect; + + return 0; +} + +/* Setup is received from transceiver. */ +static int _indicate_setup(int callref, const char *callerid, const char *dialing) +{ + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_SETUP_IND; + mncc->callref = callref; + mncc->fields |= MNCC_F_CALLING; + if (callerid) { + strncpy(mncc->calling.number, callerid, sizeof(mncc->calling.number) - 1); + mncc->calling.type = 4; /* caller ID is of type 'subscriber' */ + } // otherwise unknown and no number + mncc->fields |= MNCC_F_CALLED; + strncpy(mncc->called.number, dialing, sizeof(mncc->called.number) - 1); + mncc->called.type = 0; /* dialing is of type 'unknown' */ + mncc->lchan_type = GSM_LCHAN_TCH_F; + mncc->fields |= MNCC_F_BEARER_CAP; + mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; + mncc->bearer_cap.speech_ver[1] = -1; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup towards fixed network\n"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); + return rc; +} +int call_up_setup(int callref, const char *callerid, const char *dialing) +{ + int rc; + + if (!callref) { + PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring setup, because callref not set. (not for us)\n"); + return -CAUSE_INVALCALLREF; + } + + if (callref < 0x4000000) { + PDEBUG(DCALL, DEBUG_ERROR, "Invalid callref from mobile station, please fix!\n"); + abort(); + } + + PDEBUG(DCALL, DEBUG_INFO, "Incoming call from '%s' to '%s'\n", callerid ? : "unknown", dialing); + if (!strcmp(dialing, "010")) + PDEBUG(DCALL, DEBUG_INFO, " -> Call to Operator '%s'\n", dialing); + + + create_process(callref, PROCESS_SETUP_RO); + + rc = _indicate_setup(callref, callerid, dialing); + + return rc; +} + +/* Transceiver indicates alerting. */ +static void _indicate_alerting(int callref) +{ + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_ALERT_IND; + mncc->callref = callref; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC alerting towards fixed network\n"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); +} +void call_up_alerting(int callref) +{ + if (!callref) { + PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring alerting, because callref not set. (not for us)\n"); + return; + } + + PDEBUG(DCALL, DEBUG_INFO, "Call is alerting\n"); + + if (!send_patterns) + _indicate_alerting(callref); + set_pattern_process(callref, PATTERN_RINGBACK); + new_state_process(callref, PROCESS_ALERTING_RT); +} + +/* Transceiver indicates answer. */ +static void _indicate_answer(int callref, const char *connect_id) +{ + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_SETUP_CNF; + mncc->callref = callref; + mncc->fields |= MNCC_F_CONNECTED; + /* copy connected number as subscriber number */ + strncpy(mncc->connected.number, connect_id, sizeof(mncc->connected.number)); + mncc->connected.type = 4; + mncc->connected.plan = 1; + mncc->connected.present = 0; + mncc->connected.screen = 3; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC answer towards fixed network\n"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); +} +void call_up_answer(int callref, const char *connect_id) +{ + if (!callref) { + PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring answer, because callref not set. (not for us)\n"); + return; + } + + PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connect_id); + + if (!send_patterns) + _indicate_answer(callref, connect_id); + set_pattern_process(callref, PATTERN_NONE); + new_state_process(callref, PROCESS_CONNECT); +} + +/* Transceiver indicates release. */ +static void _indicate_disconnect_release(int callref, int cause, int disc) +{ + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = (disc) ? MNCC_DISC_IND : MNCC_REL_IND; + mncc->callref = callref; + mncc->fields |= MNCC_F_CAUSE; + mncc->cause.location = LOCATION_PRIVATE_LOCAL; + mncc->cause.value = cause; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC %s towards fixed network\n", (disc) ? "disconnect" : "release"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); +} +void call_up_release(int callref, int cause) +{ + process_t *process; + + if (!callref) { + PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring release, because callref not set. (not for us)\n"); + return; + } + + PDEBUG(DCALL, DEBUG_INFO, "Call has been released with cause=%d\n", cause); + + process = get_process(callref); + if (process) { + /* just keep MNCC connection if tones shall be sent. + * no tones while setting up / alerting the call. */ + if (send_patterns + && process->state != PROCESS_SETUP_RO + && process->state != PROCESS_ALERTING_RO) + disconnect_process(callref, cause); + else + /* if no tones shall be sent, release on disconnect + * or RO setup states */ + if (process->state == PROCESS_DISCONNECT + || process->state == PROCESS_SETUP_RO + || process->state == PROCESS_ALERTING_RO) { + destroy_process(callref); + _indicate_disconnect_release(callref, cause, 0); + /* if no tones shall be sent, disconnect on all other states */ + } else { + disconnect_process(callref, cause); + _indicate_disconnect_release(callref, cause, 1); + } + } else { + /* we don't know about the process, just send release to upper layer anyway */ + _indicate_disconnect_release(callref, cause, 0); + } +} + +/* turn recall tone on or off */ +void call_tone_recall(int callref, int on) +{ + set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE); +} + +/* forward audio to MNCC or call instance */ +void call_up_audio(int callref, sample_t *samples, int count) +{ + if (count != 160) { + fprintf(stderr, "Samples must be 160, please fix!\n"); + abort(); + } + /* is MNCC us used, forward audio */ + uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; + struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + process_t *process; + + if (!callref) + return; + + /* if we are disconnected, ignore audio */ + process = get_process(callref); + if (!process || process->pattern != PATTERN_NONE) + return; + + /* forward audio */ + data->msg_type = ANALOG_8000HZ; + data->callref = callref; +#ifdef DEBUG_LEVEL + double lev = level_of(samples, count); + printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); +#endif + samples_to_int16((int16_t *)data->data, samples, count); + + mncc_up(buf, sizeof(buf)); + /* don't destroy process here in case of an error */ +} + +/* clock that is used to transmit patterns */ +void call_clock(void) +{ + process_t *process = process_head; + uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; + struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + + while(process) { + if (process->pattern != PATTERN_NONE) { + data->msg_type = ANALOG_8000HZ; + data->callref = process->callref; + /* try to get patterns, else copy the samples we got */ + get_process_patterns(process, (int16_t *)data->data, 160); +#ifdef DEBUG_LEVEL + sample_t samples[160]; + int16_to_samples(samples, (int16_t *)data->data, 160); + double lev = level_of(samples, 160); + printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); + samples_to_int16((int16_t *)data->data, samples, 160); +#endif + mncc_up(buf, sizeof(buf)); + /* don't destroy process here in case of an error */ + } + process = process->next; + } +} + +/* mncc messages received from fixed network */ +void mncc_down(uint8_t *buf, int length) +{ + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + char number[sizeof(mncc->called.number)]; + char caller_id[sizeof(mncc->calling.number)]; + enum number_type caller_type; + int callref; + int rc; + process_t *process; + + callref = mncc->callref; + process = get_process(callref); + if (!process) { + if (mncc->msg_type == MNCC_SETUP_REQ) + process = create_process(callref, PROCESS_SETUP_RT); + else { + if (mncc->msg_type != MNCC_REL_REQ) + PDEBUG(DCALL, DEBUG_ERROR, "No process!\n"); + return; + } + } + + if (mncc->msg_type == ANALOG_8000HZ) { + struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + sample_t samples[160]; + + /* if we are disconnected, ignore audio */ + if (process->pattern != PATTERN_NONE) + return; + int16_to_samples(samples, (int16_t *)data->data, 160); +#ifdef DEBUG_LEVEL + double lev = level_of(samples, 160); + printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev))); +#endif + call_down_audio(callref, samples, 160); + return; + } + + if (process->audio_disconnected) { + switch(mncc->msg_type) { + case MNCC_DISC_REQ: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value); + + PDEBUG(DCALL, DEBUG_INFO, "Call disconnected, releasing!\n"); + + destroy_process(callref); + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n"); + mncc->msg_type = MNCC_REL_IND; + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); + break; + case MNCC_REL_REQ: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value); + + PDEBUG(DCALL, DEBUG_INFO, "Call released\n"); + + destroy_process(callref); + break; + } + return; + } + + switch(mncc->msg_type) { + case MNCC_SETUP_REQ: + strcpy(number, mncc->called.number); + + /* caller ID conversion */ + strcpy(caller_id, mncc->calling.number); + switch(mncc->calling.type) { + case 1: + caller_type = TYPE_INTERNATIONAL; + break; + case 2: + caller_type = TYPE_NATIONAL; + break; + case 4: + caller_type = TYPE_SUBSCRIBER; + break; + default: /* or 0 */ + caller_type = TYPE_UNKNOWN; + break; + } + if (!caller_id[0]) + caller_type = TYPE_NOTAVAIL; + if (mncc->calling.present == 1) + caller_type = TYPE_ANONYMOUS; + + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC call from fixed network '%s' to mobile '%s'\n", caller_id, number); + + if (mncc->callref >= 0x4000000) { + fprintf(stderr, "Invalid callref from fixed network, please fix!\n"); + abort(); + } + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC call confirm towards fixed network\n"); + memset(buf, 0, length); + mncc->msg_type = MNCC_CALL_CONF_IND; + mncc->callref = callref; + mncc->lchan_type = GSM_LCHAN_TCH_F; + mncc->fields |= MNCC_F_BEARER_CAP; + mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; + mncc->bearer_cap.speech_ver[1] = -1; + + mncc_up(buf, sizeof(struct gsm_mncc)); + + PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number); + + rc = call_down_setup(callref, caller_id, caller_type, number); + if (rc < 0) { + PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc); + if (send_patterns) { + PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n"); + _indicate_answer(callref, number); + } else { + PDEBUG(DCALL, DEBUG_INFO, "Disconnecting MNCC call towards fixed network (cause=%d)\n", -rc); + _indicate_disconnect_release(callref, -rc, 1); + } + disconnect_process(callref, -rc); + break; + } + + if (send_patterns) { + PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n"); + _indicate_answer(callref, number); + break; + } + break; + case MNCC_ALERT_REQ: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC alerting from fixed network\n"); + new_state_process(callref, PROCESS_ALERTING_RO); + break; + case MNCC_SETUP_RSP: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC answer from fixed network\n"); + new_state_process(callref, PROCESS_CONNECT); + PDEBUG(DCALL, DEBUG_INFO, "Call answered\n"); + call_down_answer(callref); + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup complete towards fixed network\n"); + memset(buf, 0, length); + mncc->msg_type = MNCC_SETUP_COMPL_IND; + mncc->callref = callref; + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); + break; + case MNCC_DISC_REQ: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value); + + process = get_process(callref); + if (process && process->state == PROCESS_CONNECT && release_on_disconnect) { + PDEBUG(DCALL, DEBUG_INFO, "Releasing, because we don't send disconnect tones to mobile phone\n"); + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n"); + mncc->msg_type = MNCC_REL_IND; + mncc_up(buf, sizeof(struct gsm_mncc)); + goto release; + } + new_state_process(callref, PROCESS_DISCONNECT); + PDEBUG(DCALL, DEBUG_INFO, "Call disconnected\n"); + call_down_disconnect(callref, mncc->cause.value); + timer_start(&process->timer, DISC_TIMEOUT); + break; + case MNCC_REL_REQ: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value); + +release: + destroy_process(callref); + PDEBUG(DCALL, DEBUG_INFO, "Call released toward mobile network\n"); + call_down_release(callref, mncc->cause.value); + break; + } +} + +int (*mncc_up)(uint8_t *buf, int length) = NULL; + +/* break down of MNCC socket */ +void mncc_flush(void) +{ + while(process_head) { + PDEBUG(DCALL, DEBUG_NOTICE, "MNCC socket closed, releasing call\n"); + call_down_release(process_head->callref, CAUSE_TEMPFAIL); + destroy_process(process_head->callref); + /* note: callref is released by sender's instance */ + } +} + diff --git a/src/libmobile/call.h b/src/libmobile/call.h new file mode 100644 index 0000000..7273a1e --- /dev/null +++ b/src/libmobile/call.h @@ -0,0 +1,40 @@ + +/* number type, includes presentation info */ +enum number_type { + TYPE_NOTAVAIL, + TYPE_ANONYMOUS, + TYPE_UNKNOWN, + TYPE_SUBSCRIBER, + TYPE_NATIONAL, + TYPE_INTERNATIONAL, +}; + +int call_init(int _send_patterns, int _release_on_disconnect); + +/* function pointer to delive MNCC messages to upper layer */ +extern int (*mncc_up)(uint8_t *buf, int length); +/* MNCC messages from upper layer */ +void mncc_down(uint8_t *buf, int length); +/* flush all calls in case of MNCC socket failure */ +void mncc_flush(void); + +/* received messages */ +int call_up_setup(int callref, const char *callerid, const char *dialing); +void call_up_alerting(int callref); +void call_up_answer(int callref, const char *connect_id); +void call_up_release(int callref, int cause); +void call_tone_recall(int callref, int on); + +/* send messages */ +int call_down_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing); +void call_down_answer(int callref); +void call_down_disconnect(int callref, int cause); +void call_down_release(int callref, int cause); + +/* send and receive audio */ +void call_up_audio(int callref, sample_t *samples, int count); +void call_down_audio(int callref, sample_t *samples, int count); + +/* clock to transmit to */ +void call_clock(void); + diff --git a/src/libmobile/display_status.c b/src/libmobile/display_status.c new file mode 100644 index 0000000..961f294 --- /dev/null +++ b/src/libmobile/display_status.c @@ -0,0 +1,147 @@ +/* display status functions + * + * (C) 2017 by Andreas Eversberg + * 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 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 . + */ + +#include +#include +#include +#include +#include +#include "../libsample/sample.h" +#include "sender.h" + +static int status_on = 0; +static int line_count = 0; +static int lines_total = 0; +static char screen[MAX_HEIGHT_STATUS][MAX_DISPLAY_WIDTH]; + +static void print_status(int on) +{ + int i, j; + int w, h; + + get_win_size(&w, &h); + + if (w > MAX_DISPLAY_WIDTH) + w = MAX_DISPLAY_WIDTH; + h--; + if (h > lines_total) + h = lines_total; + + printf("\0337\033[H\033[1;37m"); + for (i = 0; i < h; i++) { + j = 0; + if (on) { + for (j = 0; j < w; j++) + putchar(screen[i][j]); + } else { + for (j = 0; j < w; j++) + putchar(' '); + } + putchar('\n'); + } + printf("\0338"); fflush(stdout); +} + +void display_status_on(int on) +{ + if (status_on) + print_status(0); + + if (on < 0) + status_on = 1 - status_on; + else + status_on = on; + + if (status_on) + print_status(1); +} + +void display_status_limit_scroll(int on) +{ + int w, h; + + if (!status_on) + return; + + get_win_size(&w, &h); + + printf("\0337"); + printf("\033[%d;%dr", (on) ? lines_total + 1 : 1, h); + printf("\0338"); +} + +/* start status display */ +void display_status_start(void) +{ + memset(screen, ' ', sizeof(screen)); + memset(screen[0], '-', sizeof(screen[0])); + strncpy(screen[0] + 4, "Channel Status", 14); + line_count = 1; +} + +void display_status_channel(int channel, const char *type, const char *state) +{ + char line[MAX_DISPLAY_WIDTH]; + + /* add empty line after previous channel+subscriber */ + if (line_count > 1 && line_count < MAX_HEIGHT_STATUS) + line_count++; + + if (line_count == MAX_HEIGHT_STATUS) + return; + + if (type) + snprintf(line, sizeof(line), "Channel: %d Type: %s State: %s", channel, type, state); + else + snprintf(line, sizeof(line), "Channel: %d State: %s", channel, state); + line[sizeof(line) - 1] = '\0'; + strncpy(screen[line_count++], line, strlen(line)); +} + +void display_status_subscriber(const char *number, const char *state) +{ + char line[MAX_DISPLAY_WIDTH]; + + if (line_count == MAX_HEIGHT_STATUS) + return; + + if (state) + snprintf(line, sizeof(line), " Subscriber: %s State: %s", number, state); + else + snprintf(line, sizeof(line), " Subscriber: %s", number); + line[sizeof(line) - 1] = '\0'; + strncpy(screen[line_count++], line, strlen(line)); +} + +void display_status_end(void) +{ + if (line_count < MAX_HEIGHT_STATUS) { + memset(screen[line_count], '-', sizeof(screen[line_count])); + line_count++; + } + /* if last total lines exceed current line count, keep it, so removed lines are overwritten with spaces */ + if (line_count > lines_total) + lines_total = line_count; + if (status_on) + print_status(1); + /* set new total lines */ + lines_total = line_count; +} + + diff --git a/src/libmobile/main_mobile.c b/src/libmobile/main_mobile.c new file mode 100644 index 0000000..499e4c6 --- /dev/null +++ b/src/libmobile/main_mobile.c @@ -0,0 +1,688 @@ +/* Common part for main.c of each base station type + * + * (C) 2016 by Andreas Eversberg + * 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 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../libsample/sample.h" +#include "main_mobile.h" +#include "../common/debug.h" +#include "sender.h" +#include "../libtimer/timer.h" +#include "call.h" +#include "../libmncc/mncc_console.h" +#include "../libmncc/mncc_sock.h" +#include "../libmncc/mncc_cross.h" +#ifdef HAVE_SDR +#include "../libsdr/sdr.h" +#include "../libsdr/sdr_config.h" +#endif + +static int got_init = 0; + +/* common mobile settings */ +int num_kanal = 0; +int kanal[MAX_SENDER]; +int num_audiodev = 0; +const char *audiodev[MAX_SENDER] = { "hw:0,0" }; +int use_sdr = 0; +static const char *call_audiodev = ""; +int samplerate = 48000; +static int call_samplerate = 48000; +int interval = 1; +int latency = 50; +int uses_emphasis = 1; +int do_pre_emphasis = 0; +int do_de_emphasis = 0; +double rx_gain = 1.0; +static int echo_test = 0; +static int use_mncc_sock = 0; +static int use_mncc_cross = 0; +const char *mncc_name = ""; +static int send_patterns = 1; +static int release_on_disconnect = 1; +int loopback = 0; +int rt_prio = 0; +const char *write_tx_wave = NULL; +const char *write_rx_wave = NULL; +const char *read_tx_wave = NULL; +const char *read_rx_wave = NULL; + +void main_mobile_init(void) +{ + got_init = 1; +#ifdef HAVE_SDR + sdr_config_init(); +#endif +} + +void main_mobile_print_help(const char *arg0, const char *ext_usage) +{ + printf("Usage: %s -k %s[options] [station-id]\n", arg0, ext_usage); + printf("\nGlobal options:\n"); + /* - - */ + printf(" -h --help\n"); + printf(" This help\n"); + printf(" -v --verbose | ,[,[,...]] | list\n"); + printf(" Use 'list' to get a list of all levels and categories\n"); + printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel); + printf(" Verbose level+category: level digit followed by one or more categories\n"); + printf(" -> If no category is specified, all categories are selected\n"); + printf(" -k --kanal \n"); + printf(" -k --channel \n"); + printf(" Channel (German = Kanal) number of \"Sender\" (German = Transceiver)\n"); + printf(" -a --audio-device hw:,\n"); + printf(" Sound card and device number (default = '%s')\n", audiodev[0]); + printf(" Don't set it for SDR!\n"); + printf(" -s --samplerate \n"); + printf(" Sample rate of sound device (default = '%d')\n", samplerate); + printf(" -i --interval 1..25\n"); + printf(" Interval of processing loop in ms (default = '%d' ms)\n", interval); + printf(" Use 25 to drastically reduce CPU usage. In case of buffer underrun,\n"); + printf(" increase latency accordingly.\n"); + printf(" -b --buffer \n"); + printf(" How many milliseconds are processed in advance (default = '%d')\n", latency); + if (uses_emphasis) { + printf(" -p --pre-emphasis\n"); + printf(" Enable pre-emphasis, if you directly connect to the oscillator of the\n"); + printf(" transmitter. (No pre-emphasis done by the transmitter.)\n"); + printf(" -d --de-emphasis\n"); + printf(" Enable de-emphasis, if you directly connect to the discriminator of\n"); + printf(" the receiver. (No de-emphasis done by the receiver.)\n"); + } + printf(" -g --rx-gain \n"); + printf(" Raise receiver RX level by given gain in dB. This is useful if input\n"); + printf(" level of the sound device is too low, even after setting maximum level\n"); + printf(" with the mixer settings. (Works with sound card only.)\n"); + printf(" -e --echo-test\n"); + printf(" Use echo test, to send back audio from mobile phone's microphone to\n"); + printf(" the speaker. (German: 'Blasprobe').\n"); + printf(" -c --call-device hw:,\n"); + printf(" Sound card and device number for headset (default = '%s')\n", call_audiodev); + printf(" --call-samplerate \n"); + printf(" Sample rate of sound device for headset (default = '%d')\n", call_samplerate); + printf(" -x --mncc-cross\n"); + printf(" Enable built-in call forwarding between mobiles. Be sure to have\n"); + printf(" at least one control channel and two voice channels. Alternatively\n"); + printf(" use one combined control+voice channel and one voice channels.\n"); + printf(" -m --mncc-sock\n"); + printf(" Disable built-in call contol and offer socket (to LCR)\n"); + printf(" --mncc-name \n"); + printf(" '/tmp/bsc_mncc' is used by default, give name to change socket to\n"); + printf(" '/tmp/bsc_mncc_'. (Useful to run multiple networks.)\n"); + printf(" -t --tones 0 | 1\n"); + printf(" Connect call on setup/release to provide classic tones towards fixed\n"); + printf(" network (default = '%d')\n", send_patterns); + printf(" -l --loopback \n"); + printf(" Loopback test: 1 = internal | 2 = external | 3 = echo\n"); + printf(" -r --realtime \n"); + printf(" Set prio: 0 to diable, 99 for maximum (default = %d)\n", rt_prio); + printf(" --write-rx-wave \n"); + printf(" Write received audio to given wave file.\n"); + printf(" --write-tx-wave \n"); + printf(" Write transmitted audio to given wave file.\n"); + printf(" --read-rx-wave \n"); + printf(" Replace received audio by given wave file.\n"); + printf(" --read-tx-wave \n"); + printf(" Replace transmitted audio by given wave file.\n"); +#ifdef HAVE_SDR + sdr_config_print_help(); +#endif + printf("\nNetwork specific options:\n"); +} + +void main_mobile_print_hotkeys(void) +{ + printf("\n"); + printf("Press digits '0'..'9' and then 'd' key to dial towards mobile station.\n"); + printf("Press 'h' key to hangup.\n"); + printf("Press 'w' key to toggle display of RX wave form.\n"); + printf("Press 'c' key to toggle display of channel status.\n"); + printf("Press 'm' key to toggle display of measurement value.\n"); +#ifdef HAVE_SDR + sdr_config_print_hotkeys(); +#endif +} + +#define OPT_CHANNEL 1000 +#define OPT_WRITE_RX_WAVE 1001 +#define OPT_WRITE_TX_WAVE 1002 +#define OPT_READ_RX_WAVE 1003 +#define OPT_READ_TX_WAVE 1004 +#define OPT_CALL_SAMPLERATE 1005 +#define OPT_MNCC_NAME 1006 + +static struct option main_mobile_long_options[] = { + {"help", 0, 0, 'h'}, + {"debug", 1, 0, 'v'}, + {"kanal", 1, 0, 'k'}, + {"channel", 1, 0, OPT_CHANNEL}, + {"audio-device", 1, 0, 'a'}, + {"samplerate", 1, 0, 's'}, + {"interval", 1, 0, 'i'}, + {"buffer", 1, 0, 'b'}, + {"pre-emphasis", 0, 0, 'p'}, + {"de-emphasis", 0, 0, 'd'}, + {"rx-gain", 1, 0, 'g'}, + {"echo-test", 0, 0, 'e'}, + {"mncc-cross", 0, 0, 'x'}, + {"mncc-sock", 0, 0, 'm'}, + {"mncc-name", 1, 0, OPT_MNCC_NAME}, + {"call-device", 1, 0, 'c'}, + {"call-samplerate", 1, 0, OPT_CALL_SAMPLERATE}, + {"tones", 0, 0, 't'}, + {"loopback", 1, 0, 'l'}, + {"realtime", 1, 0, 'r'}, + {"write-rx-wave", 1, 0, OPT_WRITE_RX_WAVE}, + {"write-tx-wave", 1, 0, OPT_WRITE_TX_WAVE}, + {"read-rx-wave", 1, 0, OPT_READ_RX_WAVE}, + {"read-tx-wave", 1, 0, OPT_READ_TX_WAVE}, + {0, 0, 0, 0} +}; + +static const char *main_mobile_optstring = "hv:k:a:s:i:b:pdg:exmc:t:l:r:"; + +struct option *long_options; +char *optstring; + +static void check_duplicate_option(int num, struct option *option) +{ + int i; + + for (i = 0; i < num; i++) { + if (long_options[i].val == option->val) { + fprintf(stderr, "Duplicate option %d. Please fix!\n", option->val); + abort(); + } + } +} + +void main_mobile_set_options(const char *optstring_special, struct option *long_options_special) +{ + int i = 0, j; + + long_options = calloc(sizeof(*long_options), 256); + for (j = 0; main_mobile_long_options[j].name; i++, j++) { + check_duplicate_option(i, &main_mobile_long_options[j]); + memcpy(&long_options[i], &main_mobile_long_options[j], sizeof(*long_options)); + } +#ifdef HAVE_SDR + for (j = 0; sdr_config_long_options[j].name; i++, j++) { + check_duplicate_option(i, &sdr_config_long_options[j]); + memcpy(&long_options[i], &sdr_config_long_options[j], sizeof(*long_options)); + } +#endif + for (; long_options_special->name; i++) { + check_duplicate_option(i, long_options_special); + memcpy(&long_options[i], long_options_special++, sizeof(*long_options)); + } + + optstring = calloc(256, 2); + strcpy(optstring, main_mobile_optstring); +#ifdef HAVE_SDR + strcat(optstring, sdr_config_optstring); +#endif + strcat(optstring, optstring_special); +} + +void print_help(const char *arg0); + +void main_mobile_opt_switch(int c, char *arg0, int *skip_args) +{ + double gain_db; +#ifdef HAVE_SDR + int rc; +#endif + + switch (c) { + case 'h': + print_help(arg0); + exit(0); + case 'v': + if (!strcasecmp(optarg, "list")) { + debug_list_cat(); + exit(0); + } + if (parse_debug_opt(optarg)) { + fprintf(stderr, "Failed to parse debug option, please use -h for help.\n"); + exit(0); + } + *skip_args += 2; + break; + case 'k': + case OPT_CHANNEL: + OPT_ARRAY(num_kanal, kanal, atoi(optarg)) + *skip_args += 2; + break; + case 'a': + OPT_ARRAY(num_audiodev, audiodev, strdup(optarg)) + *skip_args += 2; + break; + case 's': + samplerate = atoi(optarg); + *skip_args += 2; + break; + case 'i': + interval = atoi(optarg); + *skip_args += 2; + if (interval < 1) + interval = 1; + if (interval > 25) + interval = 25; + break; + case 'b': + latency = atoi(optarg); + *skip_args += 2; + break; + case 'p': + if (!uses_emphasis) { + no_emph: + fprintf(stderr, "This network does not use emphasis, please do not enable pre- or de-emphasis! Disable emphasis on transceiver, if possible.\n"); + exit(0); + } + do_pre_emphasis = 1; + *skip_args += 1; + break; + case 'd': + if (!uses_emphasis) + goto no_emph; + do_de_emphasis = 1; + *skip_args += 1; + break; + case 'g': + gain_db = atof(optarg); + if (gain_db < 0.0) { + fprintf(stderr, "Given gain is below 0. To reduce RX signal, use sound card's mixer (or resistor net)!\n"); + exit(0); + } + rx_gain = pow(10, gain_db / 20.0); + *skip_args += 2; + break; + case 'e': + echo_test = 1; + *skip_args += 1; + break; + case 'x': + use_mncc_cross = 1; + *skip_args += 1; + break; + case 'm': + use_mncc_sock = 1; + *skip_args += 1; + break; + case OPT_MNCC_NAME: + mncc_name = strdup(optarg); + *skip_args += 2; + break; + case 'c': + call_audiodev = strdup(optarg); + *skip_args += 2; + break; + case OPT_CALL_SAMPLERATE: + call_samplerate = atoi(optarg); + *skip_args += 2; + break; + case 't': + send_patterns = atoi(optarg); + *skip_args += 2; + break; + case 'l': + loopback = atoi(optarg); + *skip_args += 2; + break; + case 'r': + rt_prio = atoi(optarg); + *skip_args += 2; + break; + case OPT_WRITE_RX_WAVE: + write_rx_wave = strdup(optarg); + *skip_args += 2; + break; + case OPT_WRITE_TX_WAVE: + write_tx_wave = strdup(optarg); + *skip_args += 2; + break; + case OPT_READ_RX_WAVE: + read_rx_wave = strdup(optarg); + *skip_args += 2; + break; + case OPT_READ_TX_WAVE: + read_tx_wave = strdup(optarg); + *skip_args += 2; + break; + default: +#ifdef HAVE_SDR + rc = sdr_config_opt_switch(c, skip_args); + if (rc < 0) + exit (0); + +#endif + break; + } +} + +/* global variable to quit main loop */ +int quit = 0; + +void sighandler(int sigset) +{ + if (sigset == SIGHUP) + return; + if (sigset == SIGPIPE) + return; + + clear_console_text(); + printf("Signal received: %d\n", sigset); + + quit = 1; +} + +static int get_char() +{ + struct timeval tv = {0, 0}; + fd_set fds; + char c = 0; + int __attribute__((__unused__)) rc; + + FD_ZERO(&fds); + FD_SET(0, &fds); + select(0+1, &fds, NULL, NULL, &tv); + if (FD_ISSET(0, &fds)) { + rc = read(0, &c, 1); + return c; + } else + return -1; +} + +/* Loop through all transceiver instances of one network. */ +void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), const char *station_id, int station_id_digits) +{ + int latspl; + sender_t *sender; + double last_time_call = 0, begin_time, now, sleep; + struct termios term, term_orig; + int c; + int rc; + + if (!got_init) { + fprintf(stderr, "main_mobile_init was not called, please fix!\n"); + abort(); + } + + /* latency of send buffer in samples */ + latspl = samplerate * latency / 1000; + + /* check MNCC support */ + if (use_mncc_cross && num_kanal == 1) { + fprintf(stderr, "You selected built-in call forwarding, but only channel is used. Does this makes sense?\n"); + return; + } + if (use_mncc_sock && use_mncc_cross) { + fprintf(stderr, "You selected MNCC socket interface and built-in call forwarding, but only one can be selected.\n"); + return; + } + if (echo_test && call_audiodev[0]) { + fprintf(stderr, "You selected call device (headset) and echo test, but only one can be selected.\n"); + return; + } + if (use_mncc_sock && call_audiodev[0]) { + fprintf(stderr, "You selected MNCC socket interface, but it cannot be used with call device (headset).\n"); + return; + } + if (use_mncc_cross && call_audiodev[0]) { + fprintf(stderr, "You selected built-in call forwarding, but it cannot be used with call device (headset).\n"); + return; + } + if (use_mncc_sock && echo_test) { + fprintf(stderr, "You selected MNCC socket interface, but it cannot be used with echo test.\n"); + return; + } + if (use_mncc_cross && echo_test) { + fprintf(stderr, "You selected built-in call forwarding, but it cannot be used with echo test.\n"); + return; + } + + /* init mncc */ + if (use_mncc_sock) { + char mncc_sock_name[64]; + if (mncc_name[0]) { + snprintf(mncc_sock_name, sizeof(mncc_sock_name), "/tmp/bsc_mncc_%s", mncc_name); + mncc_sock_name[sizeof(mncc_sock_name) - 1] = '\0'; + } else + strcpy(mncc_sock_name, "/tmp/bsc_mncc"); + rc = mncc_sock_init(mncc_sock_name); + if (rc < 0) { + fprintf(stderr, "Failed to setup MNCC socket. Quitting!\n"); + return; + } + } else if (use_mncc_cross) { + rc = mncc_cross_init(); + if (rc < 0) { + fprintf(stderr, "Failed to setup MNCC crossing process. Quitting!\n"); + return; + } + } else { + console_init(station_id, call_audiodev, call_samplerate, latency, station_id_digits, loopback, echo_test); + } + + /* init call control instance */ + rc = call_init((use_mncc_sock) ? send_patterns : 0, release_on_disconnect); + if (rc < 0) { + fprintf(stderr, "Failed to create call control instance. Quitting!\n"); + return; + } + +#ifdef HAVE_SDR + rc = sdr_configure(samplerate); + if (rc < 0) + return; +#endif + + /* open audio */ + if (sender_open_audio(latspl)) + return; + if (console_open_audio(latspl)) + return; + + /* real time priority */ + if (rt_prio > 0) { + struct sched_param schedp; + int rc; + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = rt_prio; + rc = sched_setscheduler(0, SCHED_RR, &schedp); + if (rc) + fprintf(stderr, "Error setting SCHED_RR with prio %d\n", rt_prio); + } + + /* prepare terminal */ + tcgetattr(0, &term_orig); + term = term_orig; + term.c_lflag &= ~(ISIG|ICANON|ECHO); + term.c_cc[VMIN]=1; + term.c_cc[VTIME]=2; + tcsetattr(0, TCSANOW, &term); + + /* catch signals */ + signal(SIGINT, sighandler); + signal(SIGHUP, sighandler); + signal(SIGTERM, sighandler); + signal(SIGPIPE, sighandler); + + /* start streaming */ + if (sender_start_audio()) + *quit = 1; + if (console_start_audio()) + *quit = 1; + + while(!(*quit)) { + begin_time = get_time(); + + /* process sound of all transceivers */ + for (sender = sender_head; sender; sender = sender->next) { + /* do not process audio for an audio slave, since it is done by audio master */ + if (sender->master) /* if master is set, we are an audio slave */ + continue; + process_sender_audio(sender, quit, latspl); + } + + /* process timers */ + process_timer(); + + /* process audio for mncc call instances */ + now = get_time(); + if (now - last_time_call >= 0.1) + last_time_call = now; + if (now - last_time_call >= 0.020) { + last_time_call += 0.020; + /* call clock every 20ms */ + call_clock(); + } + +next_char: + c = get_char(); + switch (c) { + case 3: + /* quit */ + clear_console_text(); + printf("CTRL+c received, quitting!\n"); + *quit = 1; + goto next_char; + case 'w': + /* toggle wave display */ + display_status_on(0); + display_measurements_on(0); +#ifdef HAVE_SDR + display_iq_on(0); + display_spectrum_on(0); +#endif + display_wave_on(-1); + goto next_char; + case 'c': + /* toggle call state display */ + display_wave_on(0); + display_measurements_on(0); +#ifdef HAVE_SDR + display_iq_on(0); + display_spectrum_on(0); +#endif + display_status_on(-1); + goto next_char; + case 'm': + /* toggle measurements display */ + display_wave_on(0); + display_status_on(0); +#ifdef HAVE_SDR + display_iq_on(0); + display_spectrum_on(0); +#endif + display_measurements_on(-1); + goto next_char; +#ifdef HAVE_SDR + case 'q': + /* toggle IQ display */ + display_wave_on(0); + display_status_on(0); + display_measurements_on(0); + display_spectrum_on(0); + display_iq_on(-1); + goto next_char; + case 's': + /* toggle spectrum display */ + display_wave_on(0); + display_status_on(0); + display_measurements_on(0); + display_iq_on(0); + display_spectrum_on(-1); + goto next_char; +#endif + case 'i': + /* dump info */ + dump_info(); + goto next_char; + } + + /* process call control */ + if (use_mncc_sock) + mncc_sock_handle(); + else if (use_mncc_cross) + mncc_cross_handle(); + else + process_console(c); + + if (myhandler) + myhandler(); + + display_measurements((double)interval / 1000.0); + + now = get_time(); + + /* sleep interval */ + sleep = ((double)interval / 1000.0) - (now - begin_time); + if (sleep > 0) + usleep(sleep * 1000000.0); + +// now = get_time(); +// printf("duration =%.6f\n", now - begin_time); + } + + /* reset signals */ + signal(SIGINT, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + + /* get rid of last entry */ + clear_console_text(); + + /* reset terminal */ + tcsetattr(0, TCSANOW, &term_orig); + + /* reset real time prio */ + if (rt_prio > 0) { + struct sched_param schedp; + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &schedp); + } + + /* cleanup call control */ + if (!use_mncc_sock && !use_mncc_cross) + console_cleanup(); + + /* close mncc socket */ + if (use_mncc_sock) + mncc_sock_exit(); + + /* close mncc forwarding */ + if (use_mncc_cross) + mncc_cross_exit(); +} + diff --git a/src/libmobile/main_mobile.h b/src/libmobile/main_mobile.h new file mode 100644 index 0000000..e958f2c --- /dev/null +++ b/src/libmobile/main_mobile.h @@ -0,0 +1,45 @@ + +extern int num_kanal; +extern int kanal[]; +extern int swap_links; +extern int num_audiodev; +extern const char *audiodev[]; +extern int use_sdr; +extern int samplerate; +extern int interval; +extern int latency; +extern int uses_emphasis; +extern int do_pre_emphasis; +extern int do_de_emphasis; +extern double rx_gain; +extern int loopback; +extern int rt_prio; +extern const char *write_rx_wave; +extern const char *write_tx_wave; +extern const char *read_rx_wave; +extern const char *read_tx_wave; + +void main_mobile_init(void); +void main_mobile_print_help(const char *arg0, const char *ext_usage); +void main_mobile_print_hotkeys(void); +extern struct option *long_options; +extern char *optstring; +void main_mobile_set_options(const char *optstring_special, struct option *long_options_special); +void main_mobile_opt_switch(int c, char *arg0, int *skip_args); + +#define OPT_ARRAY(num_name, name, value) \ +{ \ + if (num_name == MAX_SENDER) { \ + fprintf(stderr, "Too many channels defined!\n"); \ + exit(0); \ + } \ + name[num_name++] = value; \ +} + +extern int quit; +void sighandler(int sigset); + +void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), const char *station_id, int station_id_digits); + +void dump_info(void); + diff --git a/src/libmobile/sender.c b/src/libmobile/sender.c new file mode 100644 index 0000000..4e47fd7 --- /dev/null +++ b/src/libmobile/sender.c @@ -0,0 +1,449 @@ +/* Common transceiver functions + * + * (C) 2016 by Andreas Eversberg + * 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 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 . + */ + +#define CHAN sender->kanal + +#include +#include +#include +#include +#include +#include "../libsample/sample.h" +#include "../common/debug.h" +#include "sender.h" +#include "../libtimer/timer.h" + +/* debug time consumption of audio processing */ +//#define DEBUG_TIME_CONSUMPTION + +sender_t *sender_head = NULL; +static sender_t **sender_tailp = &sender_head; +int cant_recover = 0; + +/* Init transceiver instance and link to list of transceivers. */ +int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback, enum paging_signal paging_signal) +{ + sender_t *master, *slave; + int rc = 0; + + sender->kanal = kanal; + sender->sendefrequenz = sendefrequenz; + sender->empfangsfrequenz = (loopback) ? sendefrequenz : empfangsfrequenz; + strncpy(sender->audiodev, audiodev, sizeof(sender->audiodev) - 1); + sender->samplerate = samplerate; + sender->rx_gain = rx_gain; + sender->pre_emphasis = pre_emphasis; + sender->de_emphasis = de_emphasis; + sender->loopback = loopback; + sender->paging_signal = paging_signal; + sender->write_rx_wave = write_rx_wave; + sender->write_tx_wave = write_tx_wave; + sender->read_rx_wave = read_rx_wave; + sender->read_tx_wave = read_tx_wave; + + /* no gain with SDR */ + if (use_sdr) + sender->rx_gain = 1.0; + + PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Creating 'Sender' instance\n"); + + /* if we find a channel that uses the same device as we do, + * we will link us as slave to this master channel. then we + * receive and send audio via second channel of the device + * of the master channel. + */ + for (master = sender_head; master; master = master->next) { + if (master->kanal == kanal) { + PDEBUG(DSENDER, DEBUG_ERROR, "Channel %d may not be defined for multiple transceivers!\n", kanal); + rc = -EIO; + goto error; + } + if (abs(master->kanal - kanal) == 1) { + PDEBUG(DSENDER, DEBUG_NOTICE, "------------------------------------------------------------------------\n"); + PDEBUG(DSENDER, DEBUG_NOTICE, "NOTE: Channel %d is next to channel %d. This will cause interferences.\n", kanal, master->kanal); + PDEBUG(DSENDER, DEBUG_NOTICE, "Please use at least one channel distance to avoid that.\n"); + PDEBUG(DSENDER, DEBUG_NOTICE, "------------------------------------------------------------------------\n"); + } + if (!strcmp(master->audiodev, audiodev)) + break; + } + if (master) { + if (master->paging_signal != PAGING_SIGNAL_NONE && !use_sdr) { + PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because its second audio channel is used for paging signal! Use different audio device.\n", master->kanal); + rc = -EBUSY; + goto error; + } + if (paging_signal != PAGING_SIGNAL_NONE && !use_sdr) { + PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because we need a second audio channel for paging signal! Use different audio device.\n", master->kanal); + rc = -EBUSY; + goto error; + } + /* link us to a master */ + sender->master = master; + /* link master (or last slave) to us */ + for (slave = master; ; slave = slave->slave) { + if (!slave->slave) + break; + } + slave->slave = sender; + } else { + /* link audio device */ +#ifdef HAVE_SDR + if (use_sdr) { + sender->audio_open = sdr_open; + sender->audio_start = sdr_start; + sender->audio_close = sdr_close; + sender->audio_read = sdr_read; + sender->audio_write = sdr_write; + sender->audio_get_tosend = sdr_get_tosend; + } else +#endif + { + sender->audio_open = sound_open; + sender->audio_start = sound_start; + sender->audio_close = sound_close; + sender->audio_read = sound_read; + sender->audio_write = sound_write; + sender->audio_get_tosend = sound_get_tosend; + } + } + + rc = init_samplerate(&sender->srstate, 8000.0, (double)samplerate, 3300.0); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n"); + goto error; + } + + rc = jitter_create(&sender->dejitter, samplerate / 5); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init audio buffer!\n"); + goto error; + } + + rc = init_emphasis(&sender->estate, samplerate, CUT_OFF_EMPHASIS_DEFAULT); + if (rc < 0) + goto error; + + *sender_tailp = sender; + sender_tailp = &sender->next; + + display_wave_init(sender, samplerate); + display_measurements_init(sender, samplerate); + + return 0; +error: + sender_destroy(sender); + + return rc; +} + +int sender_open_audio(int latspl) +{ + sender_t *master, *inst; + int channels; + int i; + int rc; + + for (master = sender_head; master; master = master->next) { + /* skip audio slaves */ + if (master->master) + continue; + + /* get list of frequencies */ + channels = 0; + for (inst = master; inst; inst = inst->slave) { + channels++; + } + double tx_f[channels], rx_f[channels], paging_frequency = 0.0; + for (i = 0, inst = master; inst; i++, inst = inst->slave) { + tx_f[i] = inst->sendefrequenz; + rx_f[i] = inst->empfangsfrequenz; + if (inst->ruffrequenz) + paging_frequency = inst->ruffrequenz; + } + + if (master->write_rx_wave) { + rc = wave_create_record(&master->wave_rx_rec, master->write_rx_wave, master->samplerate, channels, master->max_deviation); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); + return rc; + } + } + if (master->write_tx_wave) { + rc = wave_create_record(&master->wave_tx_rec, master->write_tx_wave, master->samplerate, channels, master->max_deviation); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); + return rc; + } + } + if (master->read_rx_wave) { + rc = wave_create_playback(&master->wave_rx_play, master->read_rx_wave, master->samplerate, channels, master->max_deviation); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); + return rc; + } + } + if (master->read_tx_wave) { + rc = wave_create_playback(&master->wave_tx_play, master->read_tx_wave, master->samplerate, channels, master->max_deviation); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); + return rc; + } + } + + /* open device */ + master->audio = master->audio_open(master->audiodev, tx_f, rx_f, channels, paging_frequency, master->samplerate, latspl, master->max_deviation, master->max_modulation); + if (!master->audio) { + PDEBUG(DSENDER, DEBUG_ERROR, "No audio device!\n"); + return -EIO; + } + } + + return 0; +} + +int sender_start_audio(void) +{ + sender_t *master; + int rc = 0; + + for (master = sender_head; master; master = master->next) { + /* skip audio slaves */ + if (master->master) + continue; + + rc = master->audio_start(master->audio); + if (rc) + break; + } + + return rc; +} + +/* Destroy transceiver instance and unlink from list. */ +void sender_destroy(sender_t *sender) +{ + PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Destroying 'Sender' instance\n"); + + sender_tailp = &sender_head; + while (*sender_tailp) { + if (sender == *sender_tailp) + *sender_tailp = (*sender_tailp)->next; + else + sender_tailp = &((*sender_tailp)->next); + } + + if (sender->audio) { + sender->audio_close(sender->audio); + sender->audio = NULL; + } + + wave_destroy_record(&sender->wave_rx_rec); + wave_destroy_record(&sender->wave_tx_rec); + wave_destroy_playback(&sender->wave_rx_play); + wave_destroy_playback(&sender->wave_tx_play); + + jitter_destroy(&sender->dejitter); +} + +void sender_set_fm(sender_t *sender, double max_deviation, double max_modulation, double dBm0_deviation, double max_display) +{ + sender->max_deviation = max_deviation; + sender->max_modulation = max_modulation; + sender->dBm0_deviation = dBm0_deviation; + sender->max_display = max_display; + + PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Maxium deviation: %.1f kHz, Maximum modulation: %.1f kHz\n", max_deviation / 1000.0, max_modulation / 1000.0); + PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Deviation at dBm0 (audio level): %.1f kHz\n", dBm0_deviation / 1000.0); +} + +static void gain_samples(sample_t *samples, int length, double gain) +{ + int i; + + for (i = 0; i < length; i++) + *samples++ *= gain; +} + +/* Handle audio streaming of one transceiver. */ +void process_sender_audio(sender_t *sender, int *quit, int latspl) +{ + sender_t *inst; + int rc, count; + int num_chan, i; +#ifdef DEBUG_TIME_CONSUMPTION + static double t1, t2, t3, t4, t5, d1 = 0, d2 = 0, d3 = 0, d4 = 0, s = 0; +#endif + + /* count instances for audio channel */ + for (num_chan = 0, inst = sender; inst; num_chan++, inst = inst->slave); + sample_t buff[num_chan][latspl], *samples[num_chan]; + uint8_t pbuff[num_chan][latspl], *power[num_chan]; + enum paging_signal paging_signal[num_chan]; + int on[num_chan]; + double rf_level_db[num_chan]; + for (i = 0; i < num_chan; i++) { + samples[i] = buff[i]; + power[i] = pbuff[i]; + } + +#ifdef DEBUG_TIME_CONSUMPTION + t1 = get_time(); +#endif + count = sender->audio_get_tosend(sender->audio, latspl); + if (count < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); + if (count == -EPIPE) { + if (cant_recover) { +cant_recover: + PDEBUG(DSENDER, DEBUG_ERROR, "Cannot recover due to measurements, quitting!\n"); + *quit = 1; + return; + } + PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); + } + return; + } +#ifdef DEBUG_TIME_CONSUMPTION + t2 = get_time(); +#endif + if (count > 0) { + /* limit to our buffer */ + if (count > latspl) + count = latspl; + /* loop through all channels */ + for (i = 0, inst = sender; inst; i++, inst = inst->slave) { + /* load TX data from audio loop or from sender instance */ + if (inst->loopback == 3) + jitter_load(&inst->dejitter, samples[i], count); + else + sender_send(inst, samples[i], power[i], count); + /* internal loopback: loop back TX audio to RX */ + if (inst->loopback == 1) { + display_wave(inst, samples[i], count, inst->max_display); + sender_receive(inst, samples[i], count, 0.0); + } + /* do pre emphasis towards radio */ + if (inst->pre_emphasis) + pre_emphasis(&inst->estate, samples[i], count); + /* normal level to frequency deviation of dBm0 */ + gain_samples(samples[i], count, inst->dBm0_deviation); + /* set paging signal */ + paging_signal[i] = inst->paging_signal; + on[i] = inst->paging_on; + } + +#ifdef DEBUG_TIME_CONSUMPTION + t2 = get_time(); +#endif + if (sender->wave_tx_rec.fp) + wave_write(&sender->wave_tx_rec, samples, count); + if (sender->wave_tx_play.fp) + wave_read(&sender->wave_tx_play, samples, count); + + rc = sender->audio_write(sender->audio, samples, power, count, paging_signal, on, num_chan); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc); + if (rc == -EPIPE) { + if (cant_recover) + goto cant_recover; + PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); + } + return; + } + } +#ifdef DEBUG_TIME_CONSUMPTION + t3 = get_time(); +#endif + + count = sender->audio_read(sender->audio, samples, latspl, num_chan, rf_level_db); + if (count < 0) { + /* special case when audio_read wants us to quit */ + if (count == -EPERM) { + *quit = 1; + return; + } + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from audio device (rc = %d)!\n", count); + if (count == -EPIPE) { + if (cant_recover) + goto cant_recover; + PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); + } + return; + } +#ifdef DEBUG_TIME_CONSUMPTION + t4 = get_time(); +#endif + if (count) { + if (sender->wave_rx_rec.fp) + wave_write(&sender->wave_rx_rec, samples, count); + if (sender->wave_rx_play.fp) + wave_read(&sender->wave_rx_play, samples, count); + + /* loop through all channels */ + for (i = 0, inst = sender; inst; i++, inst = inst->slave) { + /* frequency deviation of dBm0 to normal level */ + gain_samples(samples[i], count, 1.0 / inst->dBm0_deviation); + /* rx gain */ + if (inst->rx_gain != 1.0) + gain_samples(samples[i], count, inst->rx_gain); + /* do filter and de-emphasis from radio receive audio, process echo test */ + if (inst->de_emphasis) { + dc_filter(&inst->estate, samples[i], count); + de_emphasis(&inst->estate, samples[i], count); + } + if (inst->loopback != 1) { + display_wave(inst, samples[i], count, inst->max_display); + sender_receive(inst, samples[i], count, rf_level_db[i]); + } + if (inst->loopback == 3) + jitter_save(&inst->dejitter, samples[i], count); + } + } +#ifdef DEBUG_TIME_CONSUMPTION + t5 = get_time(); + d1 += (t2 - t1); + d2 += (t3 - t2); + d3 += (t4 - t3); + d4 += (t5 - t4); + if (get_time() - s >= 1.0) { + printf("duration: %.3f (process TX), %.3f (send TX), %.3f (receive RX), %.3f (process RX)\n", d1, d2, d3, d4); + s = get_time(); + d1 = d2 = d3 = d4 = 0; + } +#endif +} + +void sender_paging(sender_t *sender, int on) +{ + sender->paging_on = on; +} + +sender_t *get_sender_by_empfangsfrequenz(double freq) +{ + sender_t *sender; + + for (sender = sender_head; sender; sender = sender->next) { + if (sender->empfangsfrequenz == freq) + return sender; + } + + return NULL; +} + diff --git a/src/libmobile/sender.h b/src/libmobile/sender.h new file mode 100644 index 0000000..4be39d1 --- /dev/null +++ b/src/libmobile/sender.h @@ -0,0 +1,101 @@ +#include "../libsound/sound.h" +#ifdef HAVE_SDR +#include "../libsdr/sdr.h" +#endif +#include "../libwave/wave.h" +#include "../libsamplerate/samplerate.h" +#include "../libjitter/jitter.h" +#include "../libemphasis/emphasis.h" +#include "../common/display.h" + +#define MAX_SENDER 16 + +/* how to send a 'paging' signal (trigger transmitter) */ +enum paging_signal { + PAGING_SIGNAL_NONE = 0, + PAGING_SIGNAL_TONE, + PAGING_SIGNAL_NOTONE, + PAGING_SIGNAL_POSITIVE, + PAGING_SIGNAL_NEGATIVE, +}; + +/* common structure of each transmitter */ +typedef struct sender { + struct sender *next; + struct sender *slave; /* points to 'slave' that uses next channel of audio device */ + struct sender *master; /* if set, the audio device is owned by 'master' */ + + /* system info */ + int kanal; /* channel number */ + double sendefrequenz; /* transmitter frequency */ + double empfangsfrequenz; /* receiver frequency */ + double ruffrequenz; /* special paging frequency used for B-Netz */ + + /* fm levels */ + double max_deviation; /* max frequency deviation */ + double max_modulation; /* max frequency modulated */ + double dBm0_deviation; /* deviation of 1000 Hz reference tone at dBm0 */ + double max_display; /* level of displaying wave form */ + + /* audio */ + void *audio; + char audiodev[64]; /* audio device name (alsa or sdr) */ + void *(*audio_open)(const char *, double *, double *, int, double, int, int, double, double); + int (*audio_start)(void *); + void (*audio_close)(void *); + int (*audio_write)(void *, sample_t **, uint8_t **, int, enum paging_signal *, int *, int); + int (*audio_read)(void *, sample_t **, int, int, double *); + int (*audio_get_tosend)(void *, int); + int samplerate; + samplerate_t srstate; /* sample rate conversion state */ + double rx_gain; /* factor of level to apply on rx samples */ + int pre_emphasis; /* use pre_emhasis, done by sender */ + int de_emphasis; /* use de_emhasis, done by sender */ + emphasis_t estate; /* pre and de emphasis */ + + /* loopback test */ + int loopback; /* 0 = off, 1 = internal, 2 = external */ + + /* record and playback */ + const char *write_rx_wave; /* file name pointers */ + const char *write_tx_wave; + const char *read_rx_wave; + const char *read_tx_wave; + wave_rec_t wave_rx_rec; /* wave recording (from rx) */ + wave_rec_t wave_tx_rec; /* wave recording (from tx) */ + wave_play_t wave_rx_play; /* wave playback (as rx) */ + wave_play_t wave_tx_play; /* wave playback (as tx) */ + + /* audio buffer for audio to send to transmitter (also used as loopback buffer) */ + jitter_t dejitter; + + /* audio buffer for audio to send to caller (20ms = 160 samples @ 8000Hz) */ + sample_t rxbuf[160]; + int rxbuf_pos; /* current fill of buffer */ + + /* paging tone */ + enum paging_signal paging_signal; /* if paging signal is used and how it is performed */ + int paging_on; /* 1 or 0 for on or off */ + + /* display wave */ + dispwav_t dispwav; /* display wave form */ + + /* display measurements */ + dispmeas_t dispmeas; /* display measurements */ +} sender_t; + +/* list of all senders */ +extern sender_t *sender_head; +extern int cant_recover; + +int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback, enum paging_signal paging_signal); +void sender_destroy(sender_t *sender); +void sender_set_fm(sender_t *sender, double max_deviation, double max_modulation, double dBm0_deviation, double max_display); +int sender_open_audio(int latspl); +int sender_start_audio(void); +void process_sender_audio(sender_t *sender, int *quit, int latspl); +void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int count); +void sender_receive(sender_t *sender, sample_t *samples, int count, double rf_level_db); +void sender_paging(sender_t *sender, int on); +sender_t *get_sender_by_empfangsfrequenz(double freq); + diff --git a/src/libsdr/display_iq.c b/src/libsdr/display_iq.c index dfe64ec..c6ab910 100644 --- a/src/libsdr/display_iq.c +++ b/src/libsdr/display_iq.c @@ -24,7 +24,7 @@ #include #include #include "../libsample/sample.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" /* must be odd value! */ #define SIZE 23 diff --git a/src/libsdr/display_spectrum.c b/src/libsdr/display_spectrum.c index a7f6150..3c885b7 100644 --- a/src/libsdr/display_spectrum.c +++ b/src/libsdr/display_spectrum.c @@ -23,7 +23,7 @@ #include #include #include "../libsample/sample.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" #include "../libfft/fft.h" #define HEIGHT 20 diff --git a/src/libsdr/sdr.c b/src/libsdr/sdr.c index f56b2b7..d9839a7 100644 --- a/src/libsdr/sdr.c +++ b/src/libsdr/sdr.c @@ -32,7 +32,7 @@ enum paging_signal; #include "../libsample/sample.h" #include "../libfm/fm.h" #include "../libtimer/timer.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" #include "sdr_config.h" #include "sdr.h" #ifdef HAVE_UHD diff --git a/src/libsound/sound_alsa.c b/src/libsound/sound_alsa.c index b3ab8b8..cfd97bd 100644 --- a/src/libsound/sound_alsa.c +++ b/src/libsound/sound_alsa.c @@ -23,7 +23,7 @@ #include #include "../libsample/sample.h" #include "../common/debug.h" -#include "../common/sender.h" +#include "../libmobile/sender.h" typedef struct sound { snd_pcm_t *phandle, *chandle; diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am index 8e9bbcf..9adf3ff 100644 --- a/src/nmt/Makefile.am +++ b/src/nmt/Makefile.am @@ -22,12 +22,12 @@ nmt_SOURCES = \ nmt_LDADD = \ $(COMMON_LA) \ libdmssms.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ $(top_builddir)/src/libdtmf/libdtmf.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/nmt/main.c b/src/nmt/main.c index 460ec57..50f4851 100644 --- a/src/nmt/main.c +++ b/src/nmt/main.c @@ -27,7 +27,7 @@ #include #include #include "../libsample/sample.h" -#include "../common/main_mobile.h" +#include "../libmobile/main_mobile.h" #include "../common/debug.h" #include "nmt.h" #include "frame.h" diff --git a/src/nmt/nmt.h b/src/nmt/nmt.h index 5179fb2..d644a79 100644 --- a/src/nmt/nmt.h +++ b/src/nmt/nmt.h @@ -1,8 +1,8 @@ -#include "../common/sender.h" +#include "../libmobile/sender.h" #include "../libtimer/timer.h" #include "../libcompandor/compandor.h" #include "../libdtmf/dtmf_encode.h" -#include "../common/call.h" +#include "../libmobile/call.h" #include "../libfsk/fsk.h" #include "../libgoertzel/goertzel.h" #include "dms.h" diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am index 6a70680..414d532 100644 --- a/src/r2000/Makefile.am +++ b/src/r2000/Makefile.am @@ -12,10 +12,10 @@ radiocom2000_SOURCES = \ main.c radiocom2000_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/r2000/main.c b/src/r2000/main.c index 4789d9e..2bd5a83 100644 --- a/src/r2000/main.c +++ b/src/r2000/main.c @@ -27,7 +27,7 @@ #include #include #include "../libsample/sample.h" -#include "../common/main_mobile.h" +#include "../libmobile/main_mobile.h" #include "../common/debug.h" #include "r2000.h" #include "dsp.h" diff --git a/src/r2000/r2000.h b/src/r2000/r2000.h index 553258b..a0dec22 100644 --- a/src/r2000/r2000.h +++ b/src/r2000/r2000.h @@ -1,7 +1,7 @@ #include "../libcompandor/compandor.h" #include "../libtimer/timer.h" -#include "../common/sender.h" -#include "../common/call.h" +#include "../libmobile/sender.h" +#include "../libmobile/call.h" #include "../libfsk/fsk.h" enum dsp_mode { diff --git a/src/tacs/Makefile.am b/src/tacs/Makefile.am index 4f57fa1..87e50fc 100644 --- a/src/tacs/Makefile.am +++ b/src/tacs/Makefile.am @@ -13,10 +13,10 @@ tacs_SOURCES = \ tacs_LDADD = \ $(COMMON_LA) \ ../amps/libamps.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ $(top_builddir)/src/libgoertzel/libgoertzel.a \ $(top_builddir)/src/libjitter/libjitter.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libtimer/libtimer.a \ $(top_builddir)/src/libsamplerate/libsamplerate.a \ diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 57cf665..e55c62d 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -13,7 +13,7 @@ test_filter_SOURCES = test_filter.c dummy.c test_filter_LDADD = \ $(COMMON_LA) \ - $(top_builddir)/src/common/libmobile.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ @@ -40,8 +40,8 @@ test_compandor_SOURCES = dummy.x test_compandor.c test_compandor_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libcompandor/libcompandor.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ @@ -52,7 +52,7 @@ test_emphasis_SOURCES = test_emphasis.c dummy.c test_emphasis_LDADD = \ $(COMMON_LA) \ - $(top_builddir)/src/common/libmobile.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ @@ -79,8 +79,8 @@ test_dms_SOURCES = test_dms.c dummy.c test_dms_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/nmt/libdmssms.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ @@ -107,8 +107,8 @@ test_sms_SOURCES = dummy.c test_sms.c test_sms_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/nmt/libdmssms.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libjitter/libjitter.a \ $(top_builddir)/src/libtimer/libtimer.a \ @@ -135,7 +135,7 @@ test_performance_SOURCES = dummy.c test_performance.c test_performance_LDADD = \ $(COMMON_LA) \ - $(top_builddir)/src/common/libmobile.a \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(top_builddir)/src/libfm/libfm.a \ $(top_builddir)/src/libfilter/libfilter.a \ @@ -148,8 +148,8 @@ test_hagelbarger_SOURCES = dummy.c test_hagelbarger.c test_hagelbarger_LDADD = \ $(COMMON_LA) \ + $(top_builddir)/src/libmobile/libmobile.a \ $(top_builddir)/src/libhagelbarger/libhagelbarger.a \ - $(top_builddir)/src/common/libmobile.a \ $(top_builddir)/src/common/libcommon.a \ $(ALSA_LIBS) \ $(UHD_LIBS) \ -- cgit v1.2.3