diff options
Diffstat (limited to 'src/ss5/main.c')
-rw-r--r-- | src/ss5/main.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/src/ss5/main.c b/src/ss5/main.c new file mode 100644 index 0000000..e4ce31a --- /dev/null +++ b/src/ss5/main.c @@ -0,0 +1,346 @@ +/* osmo-cc-ss5-endpoint main + * + * (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <termios.h> +#include "../libdebug/debug.h" +#include "../liboptions/options.h" +#include "../libg711/g711.h" +#include "ss5.h" +#include "display.h" + +ss5_endpoint_t *ss5_ep_sunset = NULL, *ss5_ep_sunrise = NULL; +int num_kanal = 2; + +int endpoints = 1; +int links = 0; +int prevent_blueboxing = 0; +int suppress_disconnect = 1; +int crosstalk = 1; +int delay_ms = 300; +int comfort_noise = 1; +double sense_db = 5; +#define MAX_CC_ARGS 1024 +static int cc_argc_sunset, cc_argc_sunrise = 0; +static const char *cc_argv_sunset[MAX_CC_ARGS], *cc_argv_sunrise[MAX_CC_ARGS]; + +static void print_usage(const char *app) +{ + printf("Usage: %s [--port <misdn port>] [--nt] [<options>]\n", app); + printf("This will create pairs of SS5 channels that are bridged together, so that\n"); + printf("calls from one link to the other can be made using SS5. The a bluebox can be\n"); + printf("used to play with it.\n"); + printf("If one endpoint is used (default), its name is 'sunset' and each pair of\n"); + printf("channels are bridged together. If two endpoints are used, their names are\n"); + printf("'sunset' and 'sunrise' and same channel index of both endpoints are bridged\n"); + printf("together.\n"); +} + +static void print_help() +{ + /* - - */ + printf(" -h --help\n"); + printf(" This help\n"); + printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | 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(" -2 --two\n"); + printf(" Create two Osmo-CC endpoints instead of one.\n"); + printf(" -c --channels\n"); + printf(" Give number of channels per endpoint. If you use a single endpoint,\n"); + printf(" you must define an even number. By default this is '2' for one\n"); + printf(" endpoint and '1' for two endpoints.\n"); + printf(" -s --suppress-disconnect 1 | 0\n"); + printf(" When a 'busy-flash' or 'release-guard' is received a disconnect is\n"); + printf(" forwarded towards OsmoCC. Set to 1 to suppress this. (Default is %d.)\n", suppress_disconnect); + printf(" -p --prevent-blueboxing 1 | 0\n"); + printf(" Prevent blueboxing by making 'release-guard' 200 ms minimum length.\n"); + printf(" -x --crosstalk 1 | 0\n"); + printf(" Enable or disable some minor crosstalk. This allows you to hear\n"); + printf(" transmitted tones at a low volume. (Default is %d.).\n", crosstalk); + printf(" -d --delay <ms> | 0\n"); + printf(" Add one-way delay to the connection between two SS5 links. This allows\n"); + printf(" to hear 'acknowlege' tones delayed. (Default is %d ms.).\n", delay_ms); + printf(" -n --comfort-noise 1 | 0\n"); + printf(" Add comfort noise whenever there is no audio from the remote link\n"); + printf(" (before or after call). (Default is %d ms.).\n", comfort_noise); + printf(" --sense 0 | <db>\n"); + printf(" Change sensitivity (level) of tone detector. A bluebox must not be\n"); + printf(" that loud. (Default is %.0f dB.).\n", sense_db); + printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n"); + printf(" --cc2 \"<osmo-cc arg>\" [--cc2 ...]\n"); + printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n"); + printf(" If you select two endpoints, use '--cc2' to pass arguments to the\n"); + printf(" second endpoint.\n"); +} + +#define OPT_SENSE 256 +#define OPT_CC2 257 + +static void add_options(void) +{ + option_add('h', "help", 0); + option_add('v', "verbose", 1); + option_add('2', "two", 0); + option_add('c', "channels", 1); + option_add('s', "suppress-disconnect", 1); + option_add('p', "prevent-blueboxing", 1); + option_add('x', "crosstalk", 1); + option_add('d', "delay", 1); + option_add('n', "comfort-noise", 1); + option_add(OPT_SENSE, "sense", 1); + option_add('C', "cc", 1); + option_add(OPT_CC2, "cc2", 1); +} + +static int handle_options(int short_option, int argi, char **argv) +{ + int rc; + + switch (short_option) { + case 'h': + print_usage(argv[0]); + print_help(); + return 0; + case 'v': + if (!strcasecmp(argv[argi], "list")) { + debug_list_cat(); + return 0; + } + rc = parse_debug_opt(argv[argi]); + if (rc < 0) { + fprintf(stderr, "Failed to parse debug option, please use -h for help.\n"); + return rc; + } + break; + case '2': + endpoints = 2; + break; + case 'c': + links = atoi(argv[argi]); + break; + case 's': + suppress_disconnect = atoi(argv[argi]); + break; + case 'p': + prevent_blueboxing = atoi(argv[argi]); + break; + case 'x': + crosstalk = atoi(argv[argi]); + break; + case 'd': + delay_ms = atoi(argv[argi]); + break; + case 'n': + comfort_noise = atoi(argv[argi]); + break; + case OPT_SENSE: + sense_db = (double)atoi(argv[argi]); + break; + case 'C': + if (!strcasecmp(argv[argi], "help")) { + osmo_cc_help(); + return 0; + } + if (cc_argc_sunset == MAX_CC_ARGS) { + fprintf(stderr, "Too many osmo-cc args!\n"); + break; + } + cc_argv_sunset[cc_argc_sunset++] = strdup(argv[argi]); + break; + case OPT_CC2: + if (!strcasecmp(argv[argi], "help")) { + osmo_cc_help(); + return 0; + } + if (cc_argc_sunrise == MAX_CC_ARGS) { + fprintf(stderr, "Too many osmo-cc args!\n"); + break; + } + cc_argv_sunrise[cc_argc_sunrise++] = strdup(argv[argi]); + break; + default: + return -EINVAL; + } + return 1; +} + +static int quit = 0; +void sighandler(int sigset) +{ + if (sigset == SIGHUP || sigset == SIGPIPE) + return; + + fprintf(stderr, "\nSignal %d received.\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; +} + +int main(int argc, char *argv[]) +{ + int argi, rc; + struct termios term, term_orig; + double now, last_time_call = 0.0; + int c; + + /* init MF */ + mf_init(0); + + /* init codecs (for recording) */ + g711_init(); + + cc_argv_sunset[cc_argc_sunset++] = strdup("remote auto"); + cc_argv_sunrise[cc_argc_sunrise++] = strdup("remote auto"); + + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/ss5/ss5.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; + + /* check links (per endpoint) */ + if (!links) + links = (endpoints == 2) ? 1 : 2; + if (links == 1 && (endpoints % 1)) { + PDEBUG(DSS5, DEBUG_ERROR, "You must define an even number of channels on a single endpoint!\n"); + goto error; + } + + /* create sunset and (optionally) sunrise */ + ss5_ep_sunset = ss5_ep_create("sunset", links, prevent_blueboxing, crosstalk, delay_ms, comfort_noise, suppress_disconnect, sense_db); + if (!ss5_ep_sunset) + goto error; + rc = osmo_cc_new(&ss5_ep_sunset->cc_ep, OSMO_CC_VERSION, "sunset", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunset, cc_argc_sunset, cc_argv_sunset); + if (rc < 0) + goto error; + if (endpoints == 2) { + ss5_ep_sunrise = ss5_ep_create("sunrise", links, prevent_blueboxing, crosstalk, delay_ms, comfort_noise, suppress_disconnect, sense_db); + if (!ss5_ep_sunrise) + goto error; + rc = osmo_cc_new(&ss5_ep_sunrise->cc_ep, OSMO_CC_VERSION, "sunrise", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunrise, cc_argc_sunrise, cc_argv_sunrise); + if (rc < 0) + goto error; + PDEBUG(DSS5, DEBUG_NOTICE, "Created endpoints 'sunset' and 'sunrise' with %d links that connect these endpoints.\n", links); + } else + PDEBUG(DSS5, DEBUG_NOTICE, "Created endpoint 'sunset' with %d links, each pair connected.\n", links); + refresh_status(); + + /* 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); + + while (!quit) { + int w; + + /* send clock calls to play/record audio files */ + 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 */ + audio_clock(ss5_ep_sunset, ss5_ep_sunrise, 160); + } + + process_timer(); + do { + w = 0; + w |= osmo_cc_handle(); + } while (w); + usleep(1000); + + /* process keyboard input */ +next_char: + c = get_char(); + switch (c) { + case 3: + printf("CTRL+c received, quitting!\n"); + quit = 1; + goto next_char; + case 'c': + display_status_on(-1); + goto next_char; + } + } + + /* reset signals */ + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + + /* reset terminal */ + tcsetattr(0, TCSANOW, &term_orig); + +error: + /* destroy endpoints */ + if (ss5_ep_sunset) { + osmo_cc_delete(&ss5_ep_sunset->cc_ep); + ss5_ep_destroy(ss5_ep_sunset); + } + if (ss5_ep_sunrise) { + osmo_cc_delete(&ss5_ep_sunrise->cc_ep); + ss5_ep_destroy(ss5_ep_sunrise); + } + + /* exit MF */ + mf_exit(); + + return 0; +} + |