aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2018-05-19 10:56:43 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2018-05-21 19:39:09 +0200
commit3b8100721032397f507b93c059d3dec0365c7eb0 (patch)
tree10d2ce93dc2bd57f33ac3e6fefa86e23d162a08c
parent6ba1b8acab77520e29ba6ba6d7e18583297a4e41 (diff)
Refactoring command line option handling
* Use own function to define and parse command line options * Command line options can be defined by config file also * --limesdr allows to auto-set required SDR option for LimeSDR
-rw-r--r--.gitignore1
-rw-r--r--configure.ac1
-rw-r--r--docs/sdr.html14
-rw-r--r--src/Makefile.am1
-rw-r--r--src/amps/Makefile.am1
-rw-r--r--src/amps/amps_tacs_main.c277
-rw-r--r--src/anetz/Makefile.am1
-rw-r--r--src/anetz/main.c125
-rw-r--r--src/bnetz/Makefile.am2
-rw-r--r--src/bnetz/dialer.c122
-rw-r--r--src/bnetz/main.c112
-rw-r--r--src/cnetz/Makefile.am1
-rw-r--r--src/cnetz/main.c356
-rw-r--r--src/jolly/Makefile.am1
-rw-r--r--src/jolly/main.c122
-rw-r--r--src/jtacs/Makefile.am1
-rw-r--r--src/libdebug/debug.c1
-rw-r--r--src/libdebug/debug.h45
-rw-r--r--src/libmobile/main_mobile.c206
-rw-r--r--src/libmobile/main_mobile.h6
-rw-r--r--src/liboptions/Makefile.am7
-rw-r--r--src/liboptions/options.c221
-rw-r--r--src/liboptions/options.h6
-rw-r--r--src/libsdr/sdr.c1
-rw-r--r--src/libsdr/sdr_config.c110
-rw-r--r--src/libsdr/sdr_config.h5
-rw-r--r--src/nmt/Makefile.am1
-rw-r--r--src/nmt/main.c262
-rw-r--r--src/r2000/Makefile.am1
-rw-r--r--src/r2000/main.c317
-rw-r--r--src/radio/Makefile.am1
-rw-r--r--src/radio/main.c277
-rw-r--r--src/tacs/Makefile.am1
-rw-r--r--src/test/Makefile.am2
-rw-r--r--src/test/test_dms.c2
-rw-r--r--src/tv/Makefile.am1
-rw-r--r--src/tv/main.c251
37 files changed, 1426 insertions, 1436 deletions
diff --git a/.gitignore b/.gitignore
index 574eb1f..a7bab40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ compile
.libs
.dirstamp
m4
+src/liboptions/liboptions.a
src/libdebug/libdebug.a
src/libmobile/libmobile.a
src/libdisplay/libdisplay.a
diff --git a/configure.ac b/configure.ac
index aa34386..c93de4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,7 @@ AS_IF([test "x$with_imagemagick" == "xyes"],[AC_MSG_NOTICE( Compiling with Image
AS_IF([test "x$with_alsa" != "xyes" -a "x$with_sdr" != "xyes"],[AC_MSG_FAILURE( Without sound nor SDR support this project does not make sense. Please support sound card for analog transceivers or better SDR!" )],[])
AC_OUTPUT(
+ src/liboptions/Makefile
src/libdebug/Makefile
src/libmobile/Makefile
src/libdisplay/Makefile
diff --git a/docs/sdr.html b/docs/sdr.html
index c4b3bf5..09bded1 100644
--- a/docs/sdr.html
+++ b/docs/sdr.html
@@ -67,7 +67,7 @@ LimeSDR
</p>
<p>
-If you have this device, you need to install the SoapySDR, then the LimeSuit and finally run configure with Osmocom Analog, compile and install.
+If you have this device, you need to install the SoapySDR, then the LimeSuite and finally run configure with Osmocom Analog, compile and install.
Run Osmocom Analog with --help again, and you should see a bunch of option for SDR.
In case of B-Netz, I use the following parameters:
</p>
@@ -75,8 +75,9 @@ In case of B-Netz, I use the following parameters:
<pre>
# bnetz --sdr-soapy \
- --sdr-tx-gain 50 \
+ --sdr-rx-antenna LNAL \
--sdr-rx-gain 30 \
+ --sdr-tx-gain 30 \
--sdr-samplerate 5000000 \
-s 100000 \
-k 17
@@ -84,6 +85,12 @@ In case of B-Netz, I use the following parameters:
</pre>
<p>
+Be sure to select the right RX antenna input.
+The frequencies we use require the low frequency filter network, so I suggest to connect your antenna to RX_1_L and select "--sdr-rx-antenna LNAL".
+Different versions of LimeSuite have different default antenna inputs, so be sure to set your RX antenna.
+</p>
+
+<p>
In order to change from analog sound card to SDR, you need <b>--sdr-soapy</b> option.
In my setup I use antennas directly connected to the SDR.
Being about 1-10 meters away, I use the <b>gain</b> as defined above.
@@ -170,7 +177,8 @@ Because C-Netz uses only odd channel numbers for 10 KHz spacing, we use channel
<pre>
# cnetz --sdr-soapy \
- --sdr-rx-gain 50 \
+ --sdr-rx-antenna LNAL \
+ --sdr-rx-gain 30 \
--sdr-tx-gain 30 \
--sdr-samplerate 5000000 \
-s 100000 \
diff --git a/src/Makefile.am b/src/Makefile.am
index aa068e1..4f1751f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,7 @@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = \
+ liboptions \
libdebug \
libmobile \
libdisplay \
diff --git a/src/amps/Makefile.am b/src/amps/Makefile.am
index 9bc972f..73118e2 100644
--- a/src/amps/Makefile.am
+++ b/src/amps/Makefile.am
@@ -26,6 +26,7 @@ amps_SOURCES = \
amps_LDADD = \
$(COMMON_LA) \
libamps.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/amps/amps_tacs_main.c b/src/amps/amps_tacs_main.c
index 9601b10..df1dca0 100644
--- a/src/amps/amps_tacs_main.c
+++ b/src/amps/amps_tacs_main.c
@@ -19,13 +19,14 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
#include "../libmobile/call.h"
+#include "../liboptions/options.h"
#include "amps.h"
#include "dsp.h"
#include "frame.h"
@@ -103,152 +104,132 @@ void print_help(const char *arg0)
main_mobile_print_hotkeys();
}
-static int handle_options(int argc, char **argv)
+static void add_options(void)
+{
+ main_mobile_add_options();
+ option_add('T', "channel-type", 1);
+ option_add('F', "flip-polarity", 1);
+ option_add('P', "ms-power", 1);
+ option_add('D', "dtx", 1);
+ option_add('S', "sysinfo", 1);
+ option_add('O', "tolerant", 0);
+}
+
+static int handle_options(int short_option, int argi, char **argv)
{
const char *p;
- int skip_args = 0;
int rc;
- static struct option long_options_special[] = {
- {"channel-type", 1, 0, 'T'},
- {"flip-polarity", 1, 0, 'F'},
- {"ms-power", 1, 0, 'P'},
- {"dtx", 1, 0, 'D'},
- {"sysinfo", 1, 0, 'S'},
- {"tolerant", 0, 0, 'O'},
- {0, 0, 0, 0}
- };
-
- main_mobile_set_options("T:F:P:D:S:O", long_options_special);
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'T':
- if (!strcmp(optarg, "list")) {
- amps_channel_list();
- exit(0);
- }
- rc = amps_channel_by_short_name(optarg);
- if (rc < 0) {
- fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg);
- exit(0);
- }
- OPT_ARRAY(num_chan_type, chan_type, rc)
- skip_args += 2;
- break;
- case 'F':
- if (!strcasecmp(optarg, "no"))
- flip_polarity = "no";
- else if (!strcasecmp(optarg, "yes"))
- flip_polarity = "yes";
- else {
- fprintf(stderr, "Given polarity '%s' is illegal, see help!\n", optarg);
- exit(0);
- }
- skip_args += 2;
- break;
- case 'P':
- ms_power = atoi(optarg);
- if (ms_power > 7)
- ms_power = 7;
- if (ms_power < 0)
- ms_power = 0;
- skip_args += 2;
- break;
- case 'D':
- dtx = atoi(optarg);
- if (dtx > 3)
- dtx = 3;
- if (dtx < 0)
- dtx = 0;
- skip_args += 2;
- break;
- case 'S':
- p = strchr(optarg, '=');
- if (!p) {
- fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, see help!\n", optarg);
- exit(0);
- }
- p++;
- if (!strncasecmp(optarg, "sid=", p - optarg)
- || !strncasecmp(optarg, "aid=", p - optarg)) {
- if (!strcasecmp(p, "list")) {
- list_stations();
- exit(0);
- }
- sid = atoi(p);
- if (sid > 32767)
- sid = 32767;
- if (sid < 0)
- sid = 0;
- } else
- if (!strncasecmp(optarg, "dcc=", p - optarg)) {
- dcc = atoi(p);
- if (dcc > 3)
- dcc = 3;
- if (dcc < 0)
- dcc = 0;
- } else
- if (!strncasecmp(optarg, "scc=", p - optarg)) {
- scc = atoi(p);
- if (scc > 2)
- scc = 2;
- if (scc < 0)
- scc = 0;
- } else
- if (!strncasecmp(optarg, "regincr=", p - optarg)) {
- regincr = atoi(p);
- } else
- if (!strncasecmp(optarg, "pureg=", p - optarg)) {
- pureg = atoi(p) & 1;
- } else
- if (!strncasecmp(optarg, "pdreg=", p - optarg)) {
- pdreg = atoi(p) & 1;
- } else
- if (!strncasecmp(optarg, "locaid=", p - optarg)) {
- locaid = atoi(p);
- if (locaid > 4095)
- locaid = 4095;
- } else
- if (!strncasecmp(optarg, "regh=", p - optarg)) {
- regh = atoi(p) & 1;
- } else
- if (!strncasecmp(optarg, "regr=", p - optarg)) {
- regr = atoi(p) & 1;
- } else
- if (!strncasecmp(optarg, "bis=", p - optarg)) {
- bis = atoi(p) & 1;
- } else {
- fprintf(stderr, "Given sysinfo parameter '%s' unknown, see help!\n", optarg);
- exit(0);
+ switch (short_option) {
+ case 'T':
+ if (!strcmp(argv[argi], "list")) {
+ amps_channel_list();
+ return 0;
+ }
+ rc = amps_channel_by_short_name(argv[argi]);
+ if (rc < 0) {
+ fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]);
+ return -EINVAL;
+ }
+ OPT_ARRAY(num_chan_type, chan_type, rc)
+ break;
+ case 'F':
+ if (!strcasecmp(argv[argi], "no"))
+ flip_polarity = "no";
+ else if (!strcasecmp(argv[argi], "yes"))
+ flip_polarity = "yes";
+ else {
+ fprintf(stderr, "Given polarity '%s' is illegal, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ break;
+ case 'P':
+ ms_power = atoi(argv[argi]);
+ if (ms_power > 7)
+ ms_power = 7;
+ if (ms_power < 0)
+ ms_power = 0;
+ break;
+ case 'D':
+ dtx = atoi(argv[argi]);
+ if (dtx > 3)
+ dtx = 3;
+ if (dtx < 0)
+ dtx = 0;
+ break;
+ case 'S':
+ p = strchr(argv[argi], '=');
+ if (!p) {
+ fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ p++;
+ if (!strncasecmp(argv[argi], "sid=", p - argv[argi])
+ || !strncasecmp(argv[argi], "aid=", p - argv[argi])) {
+ if (!strcasecmp(p, "list")) {
+ list_stations();
+ return 0;
}
- skip_args += 2;
- break;
- case 'O':
- tolerant = 1;
- skip_args += 1;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ sid = atoi(p);
+ if (sid > 32767)
+ sid = 32767;
+ if (sid < 0)
+ sid = 0;
+ } else
+ if (!strncasecmp(argv[argi], "dcc=", p - argv[argi])) {
+ dcc = atoi(p);
+ if (dcc > 3)
+ dcc = 3;
+ if (dcc < 0)
+ dcc = 0;
+ } else
+ if (!strncasecmp(argv[argi], "scc=", p - argv[argi])) {
+ scc = atoi(p);
+ if (scc > 2)
+ scc = 2;
+ if (scc < 0)
+ scc = 0;
+ } else
+ if (!strncasecmp(argv[argi], "regincr=", p - argv[argi])) {
+ regincr = atoi(p);
+ } else
+ if (!strncasecmp(argv[argi], "pureg=", p - argv[argi])) {
+ pureg = atoi(p) & 1;
+ } else
+ if (!strncasecmp(argv[argi], "pdreg=", p - argv[argi])) {
+ pdreg = atoi(p) & 1;
+ } else
+ if (!strncasecmp(argv[argi], "locaid=", p - argv[argi])) {
+ locaid = atoi(p);
+ if (locaid > 4095)
+ locaid = 4095;
+ } else
+ if (!strncasecmp(argv[argi], "regh=", p - argv[argi])) {
+ regh = atoi(p) & 1;
+ } else
+ if (!strncasecmp(argv[argi], "regr=", p - argv[argi])) {
+ regr = atoi(p) & 1;
+ } else
+ if (!strncasecmp(argv[argi], "bis=", p - argv[argi])) {
+ bis = atoi(p) & 1;
+ } else {
+ fprintf(stderr, "Given sysinfo parameter '%s' unknown, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
}
+ break;
+ case 'O':
+ tolerant = 1;
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- free(long_options);
-
- return skip_args;
+ return 1;
}
int main_amps_tacs(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int polarity;
int i;
@@ -258,12 +239,24 @@ int main_amps_tacs(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ if (!tacs) {
+ rc = options_config_file("~/.osmocom/analog/amps.conf", handle_options);
+ } else if (!jtacs) {
+ rc = options_config_file("~/.osmocom/analog/tacs.conf", handle_options);
+ } else {
+ rc = options_config_file("~/.osmocom/analog/jtacs.conf", handle_options);
+ }
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
+
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 10) {
printf("Given station ID '%s' does not have 10 digits\n", station_id);
return 0;
@@ -272,7 +265,7 @@ int main_amps_tacs(int argc, char *argv[])
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", (!tacs) ? 334 : 323);
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
if (use_sdr) {
@@ -380,7 +373,7 @@ int main_amps_tacs(int argc, char *argv[])
else if (use_sdr)
polarity = 1; /* SDR is always positive */
else {
- fprintf(stderr, "You must define, if the the TX deviation polarity has to be flipped. (-F yes | no) See help.\n");
+ fprintf(stderr, "You must define, if the the TX deviation polarity has to be flipped. (-F yes | no) use '-h' for help.\n");
exit(0);
}
diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am
index 175404d..eba47db 100644
--- a/src/anetz/Makefile.am
+++ b/src/anetz/Makefile.am
@@ -18,6 +18,7 @@ anetz_SOURCES = \
anetz_LDADD = \
$(COMMON_LA) \
libgermanton.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/anetz/main.c b/src/anetz/main.c
index 617bd88..35fc036 100644
--- a/src/anetz/main.c
+++ b/src/anetz/main.c
@@ -19,15 +19,16 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../libmobile/call.h"
+#include "../liboptions/options.h"
#include "freiton.h"
#include "besetztton.h"
#include "anetz.h"
@@ -69,79 +70,60 @@ void print_help(const char *arg0)
main_mobile_print_hotkeys();
}
-static int handle_options(int argc, char **argv)
+static void add_options(void)
+{
+ main_mobile_add_options();
+ option_add('O', "operator", 1);
+ option_add('G', "geo", 1);
+ option_add('V', "page-gain", 1);
+ option_add('P', "page-sequence", 1);
+ option_add('S', "squelch", 1);
+}
+
+static int handle_options(int short_option, int argi, char **argv)
{
- int skip_args = 0;
char *p;
double gain_db;
- static struct option long_options_special[] = {
- {"operator", 1, 0, 'O'},
- {"geo", 1, 0, 'G'},
- {"page-gain", 1, 0, 'V'},
- {"page-sequence", 1, 0, 'P'},
- {"squelch", 1, 0, 'S'},
- {0, 0, 0, 0}
- };
-
- main_mobile_set_options("O:G:V:P:S:", long_options_special);
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'O':
- strncpy(operator, optarg, sizeof(operator) - 1);
- operator[sizeof(operator) - 1] = '\0';
- skip_args += 2;
- break;
- case 'G':
- if (!strcasecmp(optarg, "list")) {
- station_list();
- exit(0);
- }
- if ((p = strchr(optarg, ','))) {
- get_station_by_coordinates(atof(optarg), atof(p + 1));
- exit(0);
- }
- fprintf(stderr, "Invalid geo parameter\n");
- exit(0);
- break;
- case 'V':
- gain_db = atof(optarg);
- page_gain = pow(10, gain_db / 20.0);
- skip_args += 2;
- break;
- case 'P':
- page_sequence = atoi(optarg);
- skip_args += 2;
- break;
- case 'S':
- if (!strcasecmp(optarg, "auto"))
- squelch_db = 0.0;
- else
- squelch_db = atof(optarg);
- skip_args += 2;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ switch (short_option) {
+ case 'O':
+ strncpy(operator, argv[argi], sizeof(operator) - 1);
+ operator[sizeof(operator) - 1] = '\0';
+ break;
+ case 'G':
+ if (!strcasecmp(argv[argi], "list")) {
+ station_list();
+ return 0;
}
+ if ((p = strchr(argv[argi], ','))) {
+ get_station_by_coordinates(atof(argv[argi]), atof(p + 1));
+ return 0;
+ }
+ fprintf(stderr, "Invalid geo parameter\n");
+ return -EINVAL;
+ case 'V':
+ gain_db = atof(argv[argi]);
+ page_gain = pow(10, gain_db / 20.0);
+ break;
+ case 'P':
+ page_sequence = atoi(argv[argi]);
+ break;
+ case 'S':
+ if (!strcasecmp(argv[argi], "auto"))
+ squelch_db = 0.0;
+ else
+ squelch_db = atof(argv[argi]);
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- free(long_options);
-
- return skip_args;
+ return 1;
}
int main(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int i;
@@ -154,12 +136,17 @@ int main(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/anetz.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 5 && strlen(station_id) != 7) {
printf("Given station ID '%s' does not have 7 or (the last) 5 digits\n", station_id);
return 0;
@@ -170,7 +157,7 @@ int main(int argc, char *argv[])
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel 30.\n\n");
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
if (use_sdr) {
diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am
index bc562e9..ecb611e 100644
--- a/src/bnetz/Makefile.am
+++ b/src/bnetz/Makefile.am
@@ -15,6 +15,7 @@ bnetz_SOURCES = \
bnetz_LDADD = \
$(COMMON_LA) \
../anetz/libgermanton.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
@@ -36,6 +37,7 @@ bnetz_dialer_SOURCES = \
dialer.c
bnetz_dialer_LDADD = \
$(COMMON_LA) \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libfsk/libfsk.a \
$(top_builddir)/src/libfm/libfm.a \
diff --git a/src/bnetz/dialer.c b/src/bnetz/dialer.c
index a3a292d..05195e3 100644
--- a/src/bnetz/dialer.c
+++ b/src/bnetz/dialer.c
@@ -19,10 +19,10 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include "../libsample/sample.h"
#include "../libfsk/fsk.h"
#include "../libwave/wave.h"
@@ -30,6 +30,7 @@
#ifdef HAVE_ALSA
#include "../libsound/sound.h"
#endif
+#include "../liboptions/options.h"
#include "telegramm.h"
#define MAX_PAUSE 0.5 /* pause before and after dialing sequence */
@@ -92,7 +93,6 @@ static void print_help(const char *arg0)
printf(" -a --audio-device hw:<card>,<device>\n");
printf(" Sound card and device number (default = '%s')\n", audiodev);
#endif
- printf(" Don't set it for SDR!\n");
printf(" -s --samplerate <rate>\n");
printf(" Sample rate of sound device (default = '%d')\n", samplerate);
printf(" -w --write-tx-wave <file>\n");
@@ -106,70 +106,50 @@ static void print_help(const char *arg0)
printf(" Indicate to base station that we are a pay phone. ('Muenztelefon')\n");
}
-static int handle_options(int argc, char **argv)
+static void add_options(void)
{
- const char *optstring;
- int skip_args = 0;
-
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"station-id", 1, 0, 'i'},
- {"audio-device", 1, 0, 'a'},
- {"samplerate", 1, 0, 's'},
- {"write-tx-wave", 1, 0, 'w'},
- {"gebuehrenimpuls", 0, 0, 'g'},
- {"metering", 0, 0, OPT_METERING},
- {"muenztelefon", 0, 0, 'm'},
- {"coin-box", 0, 0, OPT_COIN_BOX},
- {0, 0, 0, 0},
- };
-
- optstring = "hi:a:s:w:gm";
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
+ option_add('h', "help", 0);
+ option_add('i', "station-id", 1);
+ option_add('a', "audio-device", 1);
+ option_add('s', "samplerate", 1);
+ option_add('w', "write-tx-wave", 1);
+ option_add('g', "gebuehrenimpuls", 0);
+ option_add(OPT_METERING, "metering", 0);
+ option_add('m', "muenztelefon", 0);
+ option_add(OPT_COIN_BOX, "coin-box", 0);
+}
- switch (c) {
- case 'h':
- print_help(argv[0]);
- exit(0);
- case 'i':
- station_id = strdup(optarg);
- skip_args += 2;
- break;
- case 'a':
- audiodev = strdup(optarg);
- skip_args += 2;
- break;
- case 's':
- samplerate = atoi(optarg);
- skip_args += 2;
- break;
- case 'w':
- write_tx_wave = strdup(optarg);
- skip_args += 2;
- break;
- case 'g':
- case OPT_METERING:
- start_digit = 'S';
- skip_args += 1;
- break;
- case 'm':
- case OPT_COIN_BOX:
- start_digit = 'M';
- skip_args += 1;
- break;
- default:
- break;
- }
+static int handle_options(int short_option, int __attribute__((unused)) argi, char **argv)
+{
+ switch (short_option) {
+ case 'h':
+ print_help(argv[0]);
+ return 0;
+ case 'i':
+ station_id = strdup(argv[argi]);
+ break;
+ case 'a':
+ audiodev = strdup(argv[argi]);
+ break;
+ case 's':
+ samplerate = atoi(argv[argi]);
+ break;
+ case 'w':
+ write_tx_wave = strdup(argv[argi]);
+ break;
+ case 'g':
+ case OPT_METERING:
+ start_digit = 'S';
+ break;
+ case 'm':
+ case OPT_COIN_BOX:
+ start_digit = 'M';
+ break;
+ default:
+ return -EINVAL;
}
- return skip_args;
+ return 1;
}
@@ -301,10 +281,8 @@ static void process_signal(void)
int main(int argc, char *argv[])
{
- const char *arg0 = argv[0];
- int skip_args;
int i;
- int rc;
+ int rc, argi;
/* init */
bnetz_init_telegramm();
@@ -313,13 +291,15 @@ int main(int argc, char *argv[])
/* latency of send buffer in samples */
latspl = samplerate * latency / 1000;
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc <= 1) {
+ if (argi >= argc) {
printf("No phone number given!\n\n");
- print_help(arg0);
+ print_help(argv[0]);
goto exit;
}
@@ -336,7 +316,7 @@ int main(int argc, char *argv[])
}
/* check for valid phone number */
- dialing = argv[1];
+ dialing = argv[argi];
if (strlen(dialing) < 4) {
printf("Given phone number '%s' has too few digits! (less than minimum of 4 digits)\n", dialing);
goto exit;
diff --git a/src/bnetz/main.c b/src/bnetz/main.c
index d287e14..d60ba88 100644
--- a/src/bnetz/main.c
+++ b/src/bnetz/main.c
@@ -19,9 +19,9 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libdebug/debug.h"
@@ -29,6 +29,7 @@
#include "../libmobile/main_mobile.h"
#include "../anetz/freiton.h"
#include "../anetz/besetztton.h"
+#include "../liboptions/options.h"
#include "bnetz.h"
#include "dsp.h"
#include "stations.h"
@@ -79,70 +80,54 @@ void print_help(const char *arg0)
main_mobile_print_hotkeys();
}
-static int handle_options(int argc, char **argv)
+static void add_options(void)
+{
+ main_mobile_add_options();
+ option_add('G', "gfs", 1);
+ option_add('M', "gebuehrenimpuls", 1);
+ option_add('P', "paging", 1);
+ option_add('S', "squelch", 1);
+}
+
+static int handle_options(int short_option, int argi, char **argv)
{
- int skip_args = 0;
char *p;
- static struct option long_options_special[] = {
- {"gfs", 1, 0, 'G'},
- {"gebuehrenimpuls", 1, 0, 'M'},
- {"paging", 1, 0, 'P'},
- {"squelch", 1, 0, 'S'},
- {0, 0, 0, 0},
- };
-
- main_mobile_set_options("G:M:P:S:", long_options_special);
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'G':
- if (!strcasecmp(optarg, "list")) {
- station_list();
- exit(0);
- }
- if ((p = strchr(optarg, ','))) {
- gfs = get_station_by_coordinates(atof(optarg), atof(p + 1));
- if (gfs == 0)
- exit(0);
- } else
- gfs = atoi(optarg);
- skip_args += 2;
- break;
- case 'M':
- metering = atoi(optarg);
- skip_args += 2;
- break;
- case 'P':
- paging = strdup(optarg);
- skip_args += 2;
- break;
- case 'S':
- if (!strcasecmp(optarg, "auto"))
- squelch_db = 0.0;
- else
- squelch_db = atof(optarg);
- skip_args += 2;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ switch (short_option) {
+ case 'G':
+ if (!strcasecmp(argv[argi], "list")) {
+ station_list();
+ return 0;
}
+ if ((p = strchr(argv[argi], ','))) {
+ gfs = get_station_by_coordinates(atof(argv[argi]), atof(p + 1));
+ if (gfs == 0)
+ return -EINVAL;
+ } else
+ gfs = atoi(argv[argi]);
+ break;
+ case 'M':
+ metering = atoi(argv[argi]);
+ break;
+ case 'P':
+ paging = strdup(argv[argi]);
+ break;
+ case 'S':
+ if (!strcasecmp(argv[argi], "auto"))
+ squelch_db = 0.0;
+ else
+ squelch_db = atof(argv[argi]);
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- return skip_args;
+ return 1;
}
int main(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int i;
@@ -153,12 +138,17 @@ int main(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/bnetz.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 5) {
printf("Given station ID '%s' does not have 5 digits\n", station_id);
return 0;
@@ -167,7 +157,7 @@ int main(int argc, char *argv[])
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel 1 (sound card) or 17 (SDR).\n\n");
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
if (use_sdr) {
diff --git a/src/cnetz/Makefile.am b/src/cnetz/Makefile.am
index ab7cf09..5823467 100644
--- a/src/cnetz/Makefile.am
+++ b/src/cnetz/Makefile.am
@@ -17,6 +17,7 @@ cnetz_SOURCES = \
cnetz_LDADD = \
$(COMMON_LA) \
../anetz/libgermanton.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/cnetz/main.c b/src/cnetz/main.c
index 8d31cd5..c5dd916 100644
--- a/src/cnetz/main.c
+++ b/src/cnetz/main.c
@@ -19,15 +19,16 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
#include "../libmobile/call.h"
#include "../anetz/freiton.h"
#include "../anetz/besetztton.h"
+#include "../liboptions/options.h"
#include "cnetz.h"
#include "database.h"
#include "sysinfo.h"
@@ -216,198 +217,174 @@ static int atoi_limit(const char *p, int l1, int l2)
#define OPT_WARTESCHLANGE 256
-static int handle_options(int argc, char **argv)
+static void add_options(void)
+{
+ main_mobile_add_options();
+ option_add('T', "channel-type", 1);
+ option_add('M', "measure-speed", 0);
+ option_add('C', "clock-speed", 1);
+ option_add('F', "flip-polarity", 1);
+ option_add('P', "ms-power", 1);
+ option_add('A', "authentication", 0);
+ option_add('Q', "queue", 1);
+ option_add(OPT_WARTESCHLANGE, "warteschlange", 1);
+ option_add('G', "gebuehren", 1);
+ option_add('S', "sysinfo", 1);
+ option_add('D', "demod", 1);
+}
+
+static int handle_options(int short_option, int argi, char **argv)
{
- int skip_args = 0;
int rc;
const char *p;
- static struct option long_options_special[] = {
- {"channel-type", 1, 0, 'T'},
- {"measure-speed", 0, 0, 'M'},
- {"clock-speed", 1, 0, 'C'},
- {"flip-polarity", 1, 0, 'F'},
- {"ms-power", 1, 0, 'P'},
- {"authentication", 0, 0, 'A'},
- {"queue", 1, 0, 'Q'},
- {"warteschlange", 1, 0, OPT_WARTESCHLANGE},
- {"gebuehren", 1, 0, 'G'},
- {"sysinfo", 1, 0, 'S'},
- {"demod", 1, 0, 'D'},
- {0, 0, 0, 0}
- };
-
- main_mobile_set_options("T:MC:F:P:AQ:G:S:D:", long_options_special);
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'T':
- if (!strcmp(optarg, "list")) {
- cnetz_channel_list();
- exit(0);
- }
- rc = cnetz_channel_by_short_name(optarg);
- if (rc < 0) {
- fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg);
- exit(0);
- }
- OPT_ARRAY(num_chan_type, chan_type, rc)
- skip_args += 2;
- break;
- case 'M':
- measure_speed = 1;
- skip_args++;
- break;
- case 'C':
- p = strchr(optarg, ',');
- if (!p) {
- fprintf(stderr, "Illegal clock speed, use two values, seperated by comma and no spaces!\n");
- exit(0);
- }
- clock_speed[0] = strtold(optarg, NULL);
- clock_speed[1] = strtold(p + 1, NULL);
- set_clock_speed = 1;
- skip_args += 2;
- break;
- case 'F':
- if (!strcasecmp(optarg, "no"))
- flip_polarity = "no";
- else if (!strcasecmp(optarg, "yes"))
- flip_polarity = "yes";
- else if (!strcasecmp(optarg, "auto"))
- flip_polarity = "auto";
- else {
- fprintf(stderr, "Given polarity '%s' is illegal, see help!\n", optarg);
- exit(0);
- }
- skip_args += 2;
- break;
- case 'P':
- ms_power = atoi_limit(optarg, 0, 3);
- skip_args += 2;
- break;
- case 'A':
- auth = 1;
- skip_args += 1;
- break;
- case 'Q':
- case OPT_WARTESCHLANGE:
- warteschlange = atoi_limit(optarg, 0, 1);;
- skip_args += 2;
- break;
- case 'G':
- metering = atoi(optarg);
- skip_args += 2;
- break;
- case 'S':
- p = strchr(optarg, '=');
- if (!p) {
- fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, see help!\n", optarg);
- exit(0);
- }
- p++;
- if (!strncasecmp(optarg, "fuz-nat=", p - optarg)) {
- fuz_nat = atoi_limit(p, 0, 7);
- } else
- if (!strncasecmp(optarg, "fuz-fuvst=", p - optarg)) {
- fuz_fuvst = atoi_limit(p, 0, 32);
- } else
- if (!strncasecmp(optarg, "fuz-rest=", p - optarg)) {
- fuz_rest = atoi_limit(p, 0, 255);
- } else
- if (!strncasecmp(optarg, "kennung-fufst=", p - optarg)) {
- kennung_fufst = atoi_limit(p, 0, 3);
- } else
- if (!strncasecmp(optarg, "ws-kennung=", p - optarg)) {
- ws_kennung = atoi_limit(p, 0, 3);
- } else
- if (!strncasecmp(optarg, "fuvst-sperren=", p - optarg)) {
- fuvst_sperren = atoi_limit(p, 0, 3);
- } else
- if (!strncasecmp(optarg, "grenz-einbuchen=", p - optarg)) {
- grenz_einbuchen = atoi_limit(p, 0, 7);
- } else
- if (!strncasecmp(optarg, "grenz-umschalten=", p - optarg)) {
- grenz_umschalten = atoi_limit(p, 0, 15);
- } else
- if (!strncasecmp(optarg, "grenz-ausloesen=", p - optarg)) {
- grenz_ausloesen = atoi_limit(p, 0, 15);
- } else
- if (!strncasecmp(optarg, "mittel-umschalten=", p - optarg)) {
- mittel_umschalten = atoi_limit(p, 0, 5);
- } else
- if (!strncasecmp(optarg, "mittel-ausloesen=", p - optarg)) {
- mittel_ausloesen = atoi_limit(p, 0, 5);
- } else
- if (!strncasecmp(optarg, "genauigkeit=", p - optarg)) {
- genauigkeit = atoi_limit(p, 0, 1);
- } else
- if (!strncasecmp(optarg, "bewertung=", p - optarg)) {
- bewertung = atoi_limit(p, 0, 1);
- } else
- if (!strncasecmp(optarg, "entfernung=", p - optarg)) {
- entfernung = atoi_limit(p, 0, 15);
- } else
- if (!strncasecmp(optarg, "nachbar-prio=", p - optarg)) {
- nachbar_prio = atoi_limit(p, 0, 1);
- } else
- if (!strncasecmp(optarg, "futln-sperre=", p - optarg)) {
- char value[128], *v, *q;
- strncpy(value, p, sizeof(value) - 1);
- value[sizeof(value) - 1] = '\0';
- v = value;
- q = strchr(value, '-');
- if (q)
- *q++ = '\0';
- if (strlen(v) > 5)
- v += strlen(v) - 5;
- futln_sperre_start = atoi(v) & 0xf;
- if (q) {
- if (strlen(q) > 5)
- q += strlen(q) - 5;
- futln_sperre_end = atoi(q) & 0xf;
- }
- } else
- {
- fprintf(stderr, "Given sysinfo parameter '%s' unknown, see help!\n", optarg);
- exit(0);
- }
- skip_args += 2;
- break;
- case 'D':
- if (!strcasecmp(optarg, "auto"))
- demod = FSK_DEMOD_AUTO;
- else if (!strcasecmp(optarg, "slope"))
- demod = FSK_DEMOD_SLOPE;
- else if (!strcasecmp(optarg, "level"))
- demod = FSK_DEMOD_LEVEL;
- else {
- fprintf(stderr, "Given demodulation type '%s' is illegal, see help!\n", optarg);
- exit(0);
+ switch (short_option) {
+ case 'T':
+ if (!strcmp(argv[argi], "list")) {
+ cnetz_channel_list();
+ return 0;
+ }
+ rc = cnetz_channel_by_short_name(argv[argi]);
+ if (rc < 0) {
+ fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]);
+ return -EINVAL;
+ }
+ OPT_ARRAY(num_chan_type, chan_type, rc)
+ break;
+ case 'M':
+ measure_speed = 1;
+ break;
+ case 'C':
+ p = strchr(argv[argi], ',');
+ if (!p) {
+ fprintf(stderr, "Illegal clock speed, use two values, seperated by comma and no spaces!\n");
+ return -EINVAL;
+ }
+ clock_speed[0] = strtold(argv[argi], NULL);
+ clock_speed[1] = strtold(p + 1, NULL);
+ set_clock_speed = 1;
+ break;
+ case 'F':
+ if (!strcasecmp(argv[argi], "no"))
+ flip_polarity = "no";
+ else if (!strcasecmp(argv[argi], "yes"))
+ flip_polarity = "yes";
+ else if (!strcasecmp(argv[argi], "auto"))
+ flip_polarity = "auto";
+ else {
+ fprintf(stderr, "Given polarity '%s' is illegal, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ break;
+ case 'P':
+ ms_power = atoi_limit(argv[argi], 0, 3);
+ break;
+ case 'A':
+ auth = 1;
+ break;
+ case 'Q':
+ case OPT_WARTESCHLANGE:
+ warteschlange = atoi_limit(argv[argi], 0, 1);;
+ break;
+ case 'G':
+ metering = atoi(argv[argi]);
+ break;
+ case 'S':
+ p = strchr(argv[argi], '=');
+ if (!p) {
+ fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ p++;
+ if (!strncasecmp(argv[argi], "fuz-nat=", p - argv[argi])) {
+ fuz_nat = atoi_limit(p, 0, 7);
+ } else
+ if (!strncasecmp(argv[argi], "fuz-fuvst=", p - argv[argi])) {
+ fuz_fuvst = atoi_limit(p, 0, 32);
+ } else
+ if (!strncasecmp(argv[argi], "fuz-rest=", p - argv[argi])) {
+ fuz_rest = atoi_limit(p, 0, 255);
+ } else
+ if (!strncasecmp(argv[argi], "kennung-fufst=", p - argv[argi])) {
+ kennung_fufst = atoi_limit(p, 0, 3);
+ } else
+ if (!strncasecmp(argv[argi], "ws-kennung=", p - argv[argi])) {
+ ws_kennung = atoi_limit(p, 0, 3);
+ } else
+ if (!strncasecmp(argv[argi], "fuvst-sperren=", p - argv[argi])) {
+ fuvst_sperren = atoi_limit(p, 0, 3);
+ } else
+ if (!strncasecmp(argv[argi], "grenz-einbuchen=", p - argv[argi])) {
+ grenz_einbuchen = atoi_limit(p, 0, 7);
+ } else
+ if (!strncasecmp(argv[argi], "grenz-umschalten=", p - argv[argi])) {
+ grenz_umschalten = atoi_limit(p, 0, 15);
+ } else
+ if (!strncasecmp(argv[argi], "grenz-ausloesen=", p - argv[argi])) {
+ grenz_ausloesen = atoi_limit(p, 0, 15);
+ } else
+ if (!strncasecmp(argv[argi], "mittel-umschalten=", p - argv[argi])) {
+ mittel_umschalten = atoi_limit(p, 0, 5);
+ } else
+ if (!strncasecmp(argv[argi], "mittel-ausloesen=", p - argv[argi])) {
+ mittel_ausloesen = atoi_limit(p, 0, 5);
+ } else
+ if (!strncasecmp(argv[argi], "genauigkeit=", p - argv[argi])) {
+ genauigkeit = atoi_limit(p, 0, 1);
+ } else
+ if (!strncasecmp(argv[argi], "bewertung=", p - argv[argi])) {
+ bewertung = atoi_limit(p, 0, 1);
+ } else
+ if (!strncasecmp(argv[argi], "entfernung=", p - argv[argi])) {
+ entfernung = atoi_limit(p, 0, 15);
+ } else
+ if (!strncasecmp(argv[argi], "nachbar-prio=", p - argv[argi])) {
+ nachbar_prio = atoi_limit(p, 0, 1);
+ } else
+ if (!strncasecmp(argv[argi], "futln-sperre=", p - argv[argi])) {
+ char value[128], *v, *q;
+ strncpy(value, p, sizeof(value) - 1);
+ value[sizeof(value) - 1] = '\0';
+ v = value;
+ q = strchr(value, '-');
+ if (q)
+ *q++ = '\0';
+ if (strlen(v) > 5)
+ v += strlen(v) - 5;
+ futln_sperre_start = atoi(v) & 0xf;
+ if (q) {
+ if (strlen(q) > 5)
+ q += strlen(q) - 5;
+ futln_sperre_end = atoi(q) & 0xf;
}
- skip_args += 2;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ } else
+ {
+ fprintf(stderr, "Given sysinfo parameter '%s' unknown, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
}
+ break;
+ case 'D':
+ if (!strcasecmp(argv[argi], "auto"))
+ demod = FSK_DEMOD_AUTO;
+ else if (!strcasecmp(argv[argi], "slope"))
+ demod = FSK_DEMOD_SLOPE;
+ else if (!strcasecmp(argv[argi], "level"))
+ demod = FSK_DEMOD_LEVEL;
+ else {
+ fprintf(stderr, "Given demodulation type '%s' is illegal, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- free(long_options);
-
- return skip_args;
+ return 1;
}
int main(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int mandatory = 0;
int polarity;
@@ -422,12 +399,17 @@ int main(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/cnetz.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 7) {
printf("Given station ID '%s' does not have 7 digits\n", station_id);
return 0;
@@ -470,7 +452,7 @@ int main(int argc, char *argv[])
}
if (mandatory) {
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
diff --git a/src/jolly/Makefile.am b/src/jolly/Makefile.am
index e36515f..85d5fc5 100644
--- a/src/jolly/Makefile.am
+++ b/src/jolly/Makefile.am
@@ -11,6 +11,7 @@ jollycom_SOURCES = \
jollycom_LDADD = \
$(COMMON_LA) \
../anetz/libgermanton.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/jolly/main.c b/src/jolly/main.c
index 218ebfc..424b091 100644
--- a/src/jolly/main.c
+++ b/src/jolly/main.c
@@ -1,4 +1,4 @@
-/* main
+/* JollyCom main
*
* (C) 2017 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
@@ -19,11 +19,11 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
+#include <errno.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -34,6 +34,7 @@
#include "../libmncc/mncc_sock.h"
#include "../anetz/freiton.h"
#include "../anetz/besetztton.h"
+#include "../liboptions/options.h"
#include "jolly.h"
#include "dsp.h"
#include "voice.h"
@@ -70,73 +71,55 @@ void print_help(const char *arg0)
main_mobile_print_hotkeys();
}
-static int handle_options(int argc, char **argv)
+static void add_options(void)
{
- int skip_args = 0;
-
- static struct option long_options_special[] = {
- {"frequency", 1, 0, 'F'},
- {"squelch", 1, 0, 'S'},
- {"nbfm", 0, 0, 'N'},
- {"repeater", 0, 0, 'R'},
- {0, 0, 0, 0}
- };
-
- main_mobile_set_options("F:S:NR", long_options_special);
-
- while (1) {
- int option_index = 0, c;
- char *string, *string_dl, *string_ul, *string_step;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'F':
- string = strdup(optarg);
- string_dl = strsep(&string, ",");
- string_ul = strsep(&string, ",");
- string_step = strsep(&string, ",");
- if (!string_dl || !string_ul || !string_step) {
- fprintf(stderr, "Please give 3 values for --frequency, seperated by comma and no space!\n");
- exit(0);
- }
- dl_freq = atof(string_dl);
- ul_freq = atof(string_ul);
- step = atof(string_step);
- skip_args += 2;
- break;
- case 'S':
- if (!strcasecmp(optarg, "auto"))
- squelch_db = 0.0;
- else
- squelch_db = atof(optarg);
- skip_args += 2;
- break;
- case 'N':
- nbfm = 1;
- skip_args += 1;
- break;
- case 'R':
- repeater = 1;
- skip_args += 1;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ main_mobile_add_options();
+ option_add('F', "frequency", 1);
+ option_add('S', "squelch", 1);
+ option_add('N', "nbfm", 0);
+ option_add('R', "repeater", 0);
+}
+
+static int handle_options(int short_option, int argi, char **argv)
+{
+ char *string, *string_dl, *string_ul, *string_step;
+
+ switch (short_option) {
+ case 'F':
+ string = strdup(argv[argi]);
+ string_dl = strsep(&string, ",");
+ string_ul = strsep(&string, ",");
+ string_step = strsep(&string, ",");
+ if (!string_dl || !string_ul || !string_step) {
+ fprintf(stderr, "Please give 3 values for --frequency, seperated by comma and no space!\n");
+ exit(0);
}
+ dl_freq = atof(string_dl);
+ ul_freq = atof(string_ul);
+ step = atof(string_step);
+ break;
+ case 'S':
+ if (!strcasecmp(argv[argi], "auto"))
+ squelch_db = 0.0;
+ else
+ squelch_db = atof(argv[argi]);
+ break;
+ case 'N':
+ nbfm = 1;
+ break;
+ case 'R':
+ repeater = 1;
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- free(long_options);
-
- return skip_args;
+ return 1;
}
int main(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int mandatory = 0;
int i;
@@ -148,12 +131,17 @@ int main(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/jollycom.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 4) {
printf("Given station ID '%s' does not have 4 digits\n", station_id);
return 0;
@@ -178,7 +166,7 @@ int main(int argc, char *argv[])
}
if (mandatory) {
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
diff --git a/src/jtacs/Makefile.am b/src/jtacs/Makefile.am
index f2b051b..b5a8bb4 100644
--- a/src/jtacs/Makefile.am
+++ b/src/jtacs/Makefile.am
@@ -12,6 +12,7 @@ jtacs_SOURCES = \
jtacs_LDADD = \
$(COMMON_LA) \
../amps/libamps.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/libdebug/debug.c b/src/libdebug/debug.c
index fd891ec..934294b 100644
--- a/src/libdebug/debug.c
+++ b/src/libdebug/debug.c
@@ -41,6 +41,7 @@ struct debug_cat {
const char *name;
const char *color;
} debug_cat[] = {
+ { "options", "\033[1;37m" },
{ "sender", "\033[1;33m" },
{ "sound", "\033[0;35m" },
{ "dsp", "\033[0;31m" },
diff --git a/src/libdebug/debug.h b/src/libdebug/debug.h
index 8a76d45..cfc420a 100644
--- a/src/libdebug/debug.h
+++ b/src/libdebug/debug.h
@@ -4,28 +4,29 @@
#define DEBUG_NOTICE 2 /* something unexpected happens */
#define DEBUG_ERROR 3 /* there is an error with this software */
-#define DSENDER 0
-#define DSOUND 1
-#define DDSP 2
-#define DANETZ 3
-#define DBNETZ 4
-#define DCNETZ 5
-#define DNMT 6
-#define DAMPS 7
-#define DR2000 8
-#define DJOLLY 9
-#define DFRAME 10
-#define DCALL 11
-#define DMNCC 12
-#define DDB 13
-#define DTRANS 14
-#define DDMS 15
-#define DSMS 16
-#define DSDR 17
-#define DUHD 18
-#define DSOAPY 19
-#define DWAVE 20
-#define DRADIO 21
+#define DOPTIONS 0
+#define DSENDER 1
+#define DSOUND 2
+#define DDSP 3
+#define DANETZ 4
+#define DBNETZ 5
+#define DCNETZ 6
+#define DNMT 7
+#define DAMPS 8
+#define DR2000 9
+#define DJOLLY 10
+#define DFRAME 11
+#define DCALL 12
+#define DMNCC 13
+#define DDB 14
+#define DTRANS 15
+#define DDMS 16
+#define DSMS 17
+#define DSDR 18
+#define DUHD 19
+#define DSOAPY 20
+#define DWAVE 21
+#define DRADIO 22
void get_win_size(int *w, int *h);
diff --git a/src/libmobile/main_mobile.c b/src/libmobile/main_mobile.c
index a66e038..3eee1d4 100644
--- a/src/libmobile/main_mobile.c
+++ b/src/libmobile/main_mobile.c
@@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
@@ -28,7 +27,6 @@
#include <math.h>
#include <termios.h>
#include <errno.h>
-#include <getopt.h>
#include "../libsample/sample.h"
#include "main_mobile.h"
#include "../libdebug/debug.h"
@@ -42,6 +40,7 @@
#include "../libsdr/sdr.h"
#include "../libsdr/sdr_config.h"
#endif
+#include "../liboptions/options.h"
#define DEFAULT_LO_OFFSET -1000000.0
@@ -153,6 +152,8 @@ void main_mobile_print_help(const char *arg0, const char *ext_usage)
printf(" --read-tx-wave <file>\n");
printf(" Replace transmitted audio by given wave file.\n");
#ifdef HAVE_SDR
+ printf(" --limesdr\n");
+ printf(" Auto-select several required options for LimeSDR\n");
sdr_config_print_help();
#endif
printf("\nNetwork specific options:\n");
@@ -178,214 +179,167 @@ void main_mobile_print_hotkeys(void)
#define OPT_READ_TX_WAVE 1004
#define OPT_CALL_SAMPLERATE 1005
#define OPT_MNCC_NAME 1006
+#define OPT_LIMESDR 1100
-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)
+void main_mobile_add_options(void)
{
- 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));
- }
+ option_add('h', "help", 0);
+ option_add('v', "debug", 1);
+ option_add('k', "kanal", 1);
+ option_add(OPT_CHANNEL, "channel", 1);
+ option_add('a', "audio-device", 1);
+ option_add('s', "samplerate", 1);
+ option_add('i', "interval", 1);
+ option_add('b', "buffer", 1);
+ option_add('p', "pre-emphasis", 0);
+ option_add('d', "de-emphasis", 0);
+ option_add('g', "rx-gain", 1);
+ option_add('e', "echo-test", 0);
+ option_add('x', "mncc-cross", 0);
+ option_add('m', "mncc-sock", 0);
+ option_add(OPT_MNCC_NAME, "mncc-name", 1);
+ option_add('c', "call-device", 1);
+ option_add(OPT_CALL_SAMPLERATE, "call-samplerate", 1);
+ option_add('t', "tones", 0);
+ option_add('l', "loopback", 1);
+ option_add('r', "realtime", 1);
+ option_add(OPT_WRITE_RX_WAVE, "write-rx-wave", 1);
+ option_add(OPT_WRITE_TX_WAVE, "write-tx-wave", 1);
+ option_add(OPT_READ_RX_WAVE, "read-rx-wave", 1);
+ option_add(OPT_READ_TX_WAVE, "read-tx-wave", 1);
#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));
- }
+ option_add(OPT_LIMESDR, "limesdr", 0);
+ sdr_config_add_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)
+int main_mobile_handle_options(int short_option, int argi, char **argv)
{
double gain_db;
-#ifdef HAVE_SDR
int rc;
-#endif
- switch (c) {
+ switch (short_option) {
case 'h':
- print_help(arg0);
- exit(0);
+ print_help(argv[0]);
+ return 0;
case 'v':
- if (!strcasecmp(optarg, "list")) {
+ if (!strcasecmp(argv[argi], "list")) {
debug_list_cat();
- exit(0);
+ return 0;
}
- if (parse_debug_opt(optarg)) {
+ rc = parse_debug_opt(argv[argi]);
+ if (rc < 0) {
fprintf(stderr, "Failed to parse debug option, please use -h for help.\n");
- exit(0);
+ return rc;
}
- *skip_args += 2;
break;
case 'k':
case OPT_CHANNEL:
- OPT_ARRAY(num_kanal, kanal, atoi(optarg))
- *skip_args += 2;
+ OPT_ARRAY(num_kanal, kanal, atoi(argv[argi]))
break;
case 'a':
- OPT_ARRAY(num_audiodev, audiodev, strdup(optarg))
- *skip_args += 2;
+ OPT_ARRAY(num_audiodev, audiodev, strdup(argv[argi]))
break;
case 's':
- samplerate = atoi(optarg);
- *skip_args += 2;
+ samplerate = atoi(argv[argi]);
break;
case 'i':
- interval = atoi(optarg);
- *skip_args += 2;
+ interval = atoi(argv[argi]);
if (interval < 1)
interval = 1;
if (interval > 25)
interval = 25;
break;
case 'b':
- latency = atoi(optarg);
- *skip_args += 2;
+ latency = atoi(argv[argi]);
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);
+ return -EINVAL;
}
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);
+ gain_db = atof(argv[argi]);
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);
+ return -EINVAL;
}
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;
+ mncc_name = strdup(argv[argi]);
break;
case 'c':
- call_audiodev = strdup(optarg);
- *skip_args += 2;
+ call_audiodev = strdup(argv[argi]);
break;
case OPT_CALL_SAMPLERATE:
- call_samplerate = atoi(optarg);
- *skip_args += 2;
+ call_samplerate = atoi(argv[argi]);
break;
case 't':
- send_patterns = atoi(optarg);
- *skip_args += 2;
+ send_patterns = atoi(argv[argi]);
break;
case 'l':
- loopback = atoi(optarg);
- *skip_args += 2;
+ loopback = atoi(argv[argi]);
break;
case 'r':
- rt_prio = atoi(optarg);
- *skip_args += 2;
+ rt_prio = atoi(argv[argi]);
break;
case OPT_WRITE_RX_WAVE:
- write_rx_wave = strdup(optarg);
- *skip_args += 2;
+ write_rx_wave = strdup(argv[argi]);
break;
case OPT_WRITE_TX_WAVE:
- write_tx_wave = strdup(optarg);
- *skip_args += 2;
+ write_tx_wave = strdup(argv[argi]);
break;
case OPT_READ_RX_WAVE:
- read_rx_wave = strdup(optarg);
- *skip_args += 2;
+ read_rx_wave = strdup(argv[argi]);
break;
case OPT_READ_TX_WAVE:
- read_tx_wave = strdup(optarg);
- *skip_args += 2;
+ read_tx_wave = strdup(argv[argi]);
break;
+#ifdef HAVE_SDR
+ case OPT_LIMESDR:
+ {
+ char *argv_lime[] = { argv[0],
+ "--sdr-soapy",
+ "--sdr-rx-antenna", "LNAL",
+ "--sdr-rx-gain", "30",
+ "--sdr-tx-gain", "30",
+ "--sdr-samplerate", "5000000",
+ "--sdr-bandwidth", "15000000",
+ "-s", "200000",
+ };
+ int argc_lime = sizeof(argv_lime) / sizeof (*argv_lime);
+ return options_command_line(argc_lime, argv_lime, main_mobile_handle_options);
+ }
+#endif
default:
#ifdef HAVE_SDR
- rc = sdr_config_opt_switch(c, skip_args);
- if (rc < 0)
- exit (0);
-
+ return sdr_config_handle_options(short_option, argi, argv);
+#else
+ return -EINVAL;
#endif
- break;
}
+
+ return 1;
}
/* global variable to quit main loop */
diff --git a/src/libmobile/main_mobile.h b/src/libmobile/main_mobile.h
index e958f2c..4d5dffc 100644
--- a/src/libmobile/main_mobile.h
+++ b/src/libmobile/main_mobile.h
@@ -22,10 +22,8 @@ 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);
+void main_mobile_add_options(void);
+int main_mobile_handle_options(int short_option, int argi, char **argv);
#define OPT_ARRAY(num_name, name, value) \
{ \
diff --git a/src/liboptions/Makefile.am b/src/liboptions/Makefile.am
new file mode 100644
index 0000000..0d10fa7
--- /dev/null
+++ b/src/liboptions/Makefile.am
@@ -0,0 +1,7 @@
+AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
+
+noinst_LIBRARIES = liboptions.a
+
+liboptions_a_SOURCES = \
+ options.c
+
diff --git a/src/liboptions/options.c b/src/liboptions/options.c
new file mode 100644
index 0000000..e9cc25b
--- /dev/null
+++ b/src/liboptions/options.c
@@ -0,0 +1,221 @@
+/* command line options and config file parsing
+ *
+ * (C) 2018 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 <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "options.h"
+#include "../libdebug/debug.h"
+
+typedef struct option {
+ struct option *next;
+ int short_option;
+ const char *long_option;
+ int parameter_count;
+} option_t;
+
+static option_t *option_head = NULL;
+static option_t **option_tailp = &option_head;
+static int first_option = 1;
+
+void option_add(int short_option, const char *long_option, int parameter_count)
+{
+ option_t *option;
+
+ /* check if option already exists */
+ for (option = option_head; option; option = option->next) {
+ if (option->short_option == short_option
+ || !strcmp(option->long_option, long_option)) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Option '%s' added twice, please fix!\n", option->long_option);
+ abort();
+ }
+ }
+
+ option = calloc(1, sizeof(*option));
+ if (!option) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "No mem!\n");
+ abort();
+ }
+
+ option->short_option = short_option;
+ option->long_option = long_option;
+ option->parameter_count = parameter_count;
+ *option_tailp = option;
+ option_tailp = &(option->next);
+}
+
+// FIXME: support more than one option */
+int options_config_file(const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[]))
+{
+ static const char *home;
+ char config[256];
+ FILE *fp;
+ char buffer[256], opt[256], param[256], *p, *argv[1];
+ int line;
+ int rc = 1;
+ int i;
+ option_t *option;
+
+ /* open config file */
+ home = getenv("HOME");
+ if (home == NULL)
+ return 1;
+ sprintf(config, "%s/%s", home, config_file + 2);
+
+ fp = fopen(config, "r");
+ if (!fp) {
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Config file '%s' seems not to exist, using command line options only.\n", config);
+ return 1;
+ }
+
+ /* parse config file */
+ line = 0;
+ while((fgets(buffer, sizeof(buffer), fp))) {
+ line++;
+ /* prevent buffer overflow */
+ buffer[sizeof(buffer) - 1] = '\0';
+ /* cut away new-line and white spaces */
+ while (buffer[0] && buffer[strlen(buffer) - 1] <= ' ')
+ buffer[strlen(buffer) - 1] = '\0';
+ p = buffer;
+ /* remove white spaces in front of first keyword */
+ while (*p > '\0' && *p <= ' ')
+ p++;
+ /* ignore '#' lines */
+ if (*p == '#')
+ continue;
+ /* get option form line */
+ i = 0;
+ while (*p > ' ')
+ opt[i++] = *p++;
+ opt[i] = '\0';
+ if (opt[0] == '\0')
+ continue;
+ /* skip white spaces behind option */
+ while (*p > '\0' && *p <= ' ')
+ p++;
+ /* get param from line */
+ i = 0;
+ while (*p > ' ')
+ param[i++] = *p++;
+ param[i] = '\0';
+ /* search option */
+ for (option = option_head; option; option = option->next) {
+ if (opt[0] == option->short_option && opt[1] == '\0') {
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Config file option '%s' ('%s'), parameter '%s'\n", opt, option->long_option, param);
+ break;
+ }
+ if (!strcmp(opt, option->long_option)) {
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Config file option '%s', parameter '%s'\n", opt, param);
+ break;
+ }
+ }
+ if (!option) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d is not a valid option, use '-h' for help!\n", opt, config_file, line);
+ rc = -EINVAL;
+ goto done;
+ }
+ if (option->parameter_count && !param[0]) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d requires %d parameter(s), use '-h' for help!\n", opt, config_file, line, option->parameter_count);
+ return -EINVAL;
+ }
+ argv[0] = param;
+ rc = handle_options(option->short_option, 0, argv);
+ if (rc <= 0)
+ goto done;
+ first_option = 0;
+ }
+
+done:
+ /* close config file */
+ fclose(fp);
+
+ return rc;
+}
+
+int options_command_line(int argc, char *argv[], int (*handle_options)(int short_option, int argi, char *argv[]))
+{
+ option_t *option;
+ int argi, i;
+ int rc;
+
+ for (argi = 1; argi < argc; argi++) {
+ if (argv[argi][0] == '-') {
+ if (argv[argi][1] != '-') {
+ if (strlen(argv[argi]) != 2) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' exceeds one character, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ /* -x */
+ for (option = option_head; option; option = option->next) {
+ if (argv[argi][1] == option->short_option) {
+ if (option->parameter_count && argi + option->parameter_count < argc)
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s' ('--%s'), parameter '%s'\n", argv[argi], option->long_option, argv[argi + 1]);
+ else
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s' ('--%s')\n", argv[argi], option->long_option);
+ break;
+ }
+ }
+ } else {
+ /* --xxxxxx */
+ for (option = option_head; option; option = option->next) {
+ if (!strcmp(argv[argi] + 2, option->long_option)) {
+ if (option->parameter_count && argi + option->parameter_count < argc)
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s', parameter '%s'\n", argv[argi], argv[argi + 1]);
+ else
+ PDEBUG(DOPTIONS, DEBUG_INFO, "Command line option '%s'\n", argv[argi]);
+ break;
+ }
+ }
+ }
+ if (!option) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' is not a valid option, use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
+ }
+ if (argi + option->parameter_count >= argc) {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' requires %d parameter(s), use '-h' for help!\n", argv[argi], option->parameter_count);
+ return -EINVAL;
+ }
+ rc = handle_options(option->short_option, argi + 1, argv);
+ if (rc <= 0)
+ return rc;
+ first_option = 0;
+ argi += option->parameter_count;
+ } else
+ break;
+ }
+
+ /* no more options, so we check if there is an option after a non-option parameter */
+ for (i = argi; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' behind command line parameter '%s' not allowed! Please put all command line options before command line parameter(s).\n", argv[i], argv[argi]);
+ return -EINVAL;
+ }
+ }
+
+ return argi;
+}
+
+int option_is_first(void)
+{
+ return first_option;
+}
+
diff --git a/src/liboptions/options.h b/src/liboptions/options.h
new file mode 100644
index 0000000..6f7e41a
--- /dev/null
+++ b/src/liboptions/options.h
@@ -0,0 +1,6 @@
+
+void option_add(int short_option, const char *long_option, int parameter_count);
+int options_config_file(const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[]));
+int options_command_line(int argc, char *argv[], int (*handle_options)(int short_option, int argi, char *argv[]));
+int option_is_first(void);
+
diff --git a/src/libsdr/sdr.c b/src/libsdr/sdr.c
index dec6ab6..0bcdf9a 100644
--- a/src/libsdr/sdr.c
+++ b/src/libsdr/sdr.c
@@ -25,7 +25,6 @@ enum paging_signal;
#include <string.h>
#include <errno.h>
#include <math.h>
-#include <getopt.h>
#define __USE_GNU
#include <pthread.h>
#include <unistd.h>
diff --git a/src/libsdr/sdr_config.c b/src/libsdr/sdr_config.c
index 8fbb87c..dfbada7 100644
--- a/src/libsdr/sdr_config.c
+++ b/src/libsdr/sdr_config.c
@@ -23,8 +23,9 @@ enum paging_signal;
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
-#include <getopt.h>
+#include <errno.h>
#include "../libsample/sample.h"
+#include "../liboptions/options.h"
#include "sdr.h"
#include "sdr_config.h"
@@ -122,43 +123,40 @@ void sdr_config_print_hotkeys(void)
#define OPT_SDR_SWAP_LINKS 1517
#define OPT_SDR_UHD_TX_TS 1518
-struct option sdr_config_long_options[] = {
- {"sdr-uhd", 0, 0, OPT_SDR_UHD},
- {"sdr-soapy", 0, 0, OPT_SDR_SOAPY},
- {"sdr-channel", 1, 0, OPT_SDR_CHANNEL},
- {"sdr-device-args", 1, 0, OPT_SDR_DEVICE_ARGS},
- {"sdr-stream-args", 1, 0, OPT_SDR_STREAM_ARGS},
- {"sdr-tune-args", 1, 0, OPT_SDR_TUNE_ARGS},
- {"sdr-samplerate", 1, 0, OPT_SDR_SAMPLERATE},
- {"sdr-lo-offset", 1, 0, OPT_SDR_LO_OFFSET},
- {"sdr-bandwidth", 1, 0, OPT_SDR_BANDWIDTH},
- {"sdr-rx-antenna", 1, 0, OPT_SDR_RX_ANTENNA},
- {"sdr-tx-antenna", 1, 0, OPT_SDR_TX_ANTENNA},
- {"sdr-rx-gain", 1, 0, OPT_SDR_RX_GAIN},
- {"sdr-tx-gain", 1, 0, OPT_SDR_TX_GAIN},
- {"write-iq-rx-wave", 1, 0, OPT_WRITE_IQ_RX_WAVE},
- {"write-iq-tx-wave", 1, 0, OPT_WRITE_IQ_TX_WAVE},
- {"read-iq-rx-wave", 1, 0, OPT_READ_IQ_RX_WAVE},
- {"read-iq-tx-wave", 1, 0, OPT_READ_IQ_TX_WAVE},
- {"sdr-swap-links", 0, 0, OPT_SDR_SWAP_LINKS},
- {"sdr-uhd-tx-timestamps", 0, 0, OPT_SDR_UHD_TX_TS},
- {0, 0, 0, 0}
-};
-
-const char *sdr_config_optstring = "";
+void sdr_config_add_options(void)
+{
+ option_add(OPT_SDR_UHD, "sdr-uhd", 0);
+ option_add(OPT_SDR_SOAPY, "sdr-soapy", 0);
+ option_add(OPT_SDR_CHANNEL, "sdr-channel", 1);
+ option_add(OPT_SDR_DEVICE_ARGS, "sdr-device-args", 1);
+ option_add(OPT_SDR_STREAM_ARGS, "sdr-stream-args", 1);
+ option_add(OPT_SDR_TUNE_ARGS, "sdr-tune-args", 1);
+ option_add(OPT_SDR_SAMPLERATE, "sdr-samplerate", 1);
+ option_add(OPT_SDR_LO_OFFSET, "sdr-lo-offset", 1);
+ option_add(OPT_SDR_BANDWIDTH, "sdr-bandwidth", 1);
+ option_add(OPT_SDR_RX_ANTENNA, "sdr-rx-antenna", 1);
+ option_add(OPT_SDR_TX_ANTENNA, "sdr-tx-antenna", 1);
+ option_add(OPT_SDR_RX_GAIN, "sdr-rx-gain", 1);
+ option_add(OPT_SDR_TX_GAIN, "sdr-tx-gain", 1);
+ option_add(OPT_WRITE_IQ_RX_WAVE, "write-iq-rx-wave", 1);
+ option_add(OPT_WRITE_IQ_TX_WAVE, "write-iq-tx-wave", 1);
+ option_add(OPT_READ_IQ_RX_WAVE, "read-iq-rx-wave", 1);
+ option_add(OPT_READ_IQ_TX_WAVE, "read-iq-tx-wave", 1);
+ option_add(OPT_SDR_SWAP_LINKS, "sdr-swap-links", 0);
+ option_add(OPT_SDR_UHD_TX_TS, "sdr-uhd-tx-timestamps", 0);
+}
-int sdr_config_opt_switch(int c, int *skip_args)
+int sdr_config_handle_options(int short_option, int argi, char **argv)
{
- switch (c) {
+ switch (short_option) {
case OPT_SDR_UHD:
#ifdef HAVE_UHD
sdr_config->uhd = 1;
use_sdr = 1;
#else
fprintf(stderr, "UHD SDR support not compiled in!\n");
- exit(0);
+ return -EINVAL;
#endif
- *skip_args += 1;
break;
case OPT_SDR_SOAPY:
#ifdef HAVE_SOAPY
@@ -166,83 +164,65 @@ int sdr_config_opt_switch(int c, int *skip_args)
use_sdr = 1;
#else
fprintf(stderr, "SoapySDR support not compiled in!\n");
- exit(0);
+ return -EINVAL;
#endif
- *skip_args += 1;
break;
case OPT_SDR_CHANNEL:
- sdr_config->channel = atoi(optarg);
- *skip_args += 2;
+ sdr_config->channel = atoi(argv[argi]);
break;
case OPT_SDR_DEVICE_ARGS:
- sdr_config->device_args = strdup(optarg);
- *skip_args += 2;
+ sdr_config->device_args = strdup(argv[argi]);
break;
case OPT_SDR_STREAM_ARGS:
- sdr_config->stream_args = strdup(optarg);
- *skip_args += 2;
+ sdr_config->stream_args = strdup(argv[argi]);
break;
case OPT_SDR_TUNE_ARGS:
- sdr_config->tune_args = strdup(optarg);
- *skip_args += 2;
+ sdr_config->tune_args = strdup(argv[argi]);
break;
case OPT_SDR_SAMPLERATE:
- sdr_config->samplerate = atoi(optarg);
- *skip_args += 2;
+ sdr_config->samplerate = atoi(argv[argi]);
break;
case OPT_SDR_LO_OFFSET:
- sdr_config->lo_offset = atof(optarg);
- *skip_args += 2;
+ sdr_config->lo_offset = atof(argv[argi]);
break;
case OPT_SDR_BANDWIDTH:
- sdr_config->bandwidth = atof(optarg);
- *skip_args += 2;
+ sdr_config->bandwidth = atof(argv[argi]);
break;
case OPT_SDR_RX_ANTENNA:
- sdr_config->rx_antenna = strdup(optarg);
- *skip_args += 2;
+ sdr_config->rx_antenna = strdup(argv[argi]);
break;
case OPT_SDR_TX_ANTENNA:
- sdr_config->tx_antenna = strdup(optarg);
- *skip_args += 2;
+ sdr_config->tx_antenna = strdup(argv[argi]);
break;
case OPT_SDR_RX_GAIN:
- sdr_config->rx_gain = atof(optarg);
- *skip_args += 2;
+ sdr_config->rx_gain = atof(argv[argi]);
break;
case OPT_SDR_TX_GAIN:
- sdr_config->tx_gain = atof(optarg);
- *skip_args += 2;
+ sdr_config->tx_gain = atof(argv[argi]);
break;
case OPT_WRITE_IQ_RX_WAVE:
- sdr_config->write_iq_rx_wave = strdup(optarg);
- *skip_args += 2;
+ sdr_config->write_iq_rx_wave = strdup(argv[argi]);
break;
case OPT_WRITE_IQ_TX_WAVE:
- sdr_config->write_iq_tx_wave = strdup(optarg);
- *skip_args += 2;
+ sdr_config->write_iq_tx_wave = strdup(argv[argi]);
break;
case OPT_READ_IQ_RX_WAVE:
- sdr_config->read_iq_rx_wave = strdup(optarg);
- *skip_args += 2;
+ sdr_config->read_iq_rx_wave = strdup(argv[argi]);
break;
case OPT_READ_IQ_TX_WAVE:
- sdr_config->read_iq_tx_wave = strdup(optarg);
- *skip_args += 2;
+ sdr_config->read_iq_tx_wave = strdup(argv[argi]);
break;
case OPT_SDR_SWAP_LINKS:
sdr_config->swap_links = 1;
- *skip_args += 1;
break;
case OPT_SDR_UHD_TX_TS:
sdr_config->uhd_tx_timestamps = 1;
- *skip_args += 1;
break;
default:
- return -1;
+ return -EINVAL;
}
- return 0;
+ return 1;
}
int sdr_configure(int samplerate)
diff --git a/src/libsdr/sdr_config.h b/src/libsdr/sdr_config.h
index 9bfba1f..1feb323 100644
--- a/src/libsdr/sdr_config.h
+++ b/src/libsdr/sdr_config.h
@@ -26,8 +26,7 @@ extern sdr_config_t *sdr_config;
void sdr_config_init(double lo_offset);
void sdr_config_print_help(void);
void sdr_config_print_hotkeys(void);
-extern struct option sdr_config_long_options[];
-extern const char *sdr_config_optstring;
-int sdr_config_opt_switch(int c, int *skip_args);
+void sdr_config_add_options(void);
+int sdr_config_handle_options(int short_option, int argi, char **argv);
int sdr_configure(int samplerate);
diff --git a/src/nmt/Makefile.am b/src/nmt/Makefile.am
index cee6953..5f15ff4 100644
--- a/src/nmt/Makefile.am
+++ b/src/nmt/Makefile.am
@@ -22,6 +22,7 @@ nmt_SOURCES = \
nmt_LDADD = \
$(COMMON_LA) \
libdmssms.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/nmt/main.c b/src/nmt/main.c
index ad8eb56..1d3eb2c 100644
--- a/src/nmt/main.c
+++ b/src/nmt/main.c
@@ -19,16 +19,17 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
+#include "../liboptions/options.h"
#include "nmt.h"
#include "frame.h"
#include "dsp.h"
@@ -97,141 +98,118 @@ void print_help(const char *arg0)
main_mobile_print_hotkeys();
}
-static int handle_options(int argc, char **argv)
+static void add_options(void)
{
+ main_mobile_add_options();
+ option_add('N', "nmt-system", 1);
+ option_add('T', "channel-type", 1);
+ option_add('P', "ms-power", 1);
+ option_add('Y', "traffic-area", 1);
+ option_add('A', "area-number", 1);
+ option_add('C', "compandor", 1);
+ option_add('0', "supervisory", 1);
+ option_add('S', "smsc-number", 1);
+ option_add('I', "caller-id", 1);
+}
+
+static int handle_options(int short_option, int argi, char **argv)
+{
+ int rc;
char *p;
int super;
- int skip_args = 0;
-
- static struct option long_options_special[] = {
- {"nmt-system", 1, 0, 'N'},
- {"channel-type", 1, 0, 'T'},
- {"ms-power", 1, 0, 'P'},
- {"traffic-area", 1, 0, 'Y'},
- {"area-number", 1, 0, 'A'},
- {"compandor", 1, 0, 'C'},
- {"supervisory", 1, 0, '0'},
- {"smsc-number", 1, 0, 'S'},
- {"caller-id", 1, 0, 'I'},
- {0, 0, 0, 0}
- };
-
- main_mobile_set_options("N:T:P:Y:A:C:0:S:I:", long_options_special);
-
- while (1) {
- int option_index = 0, c, rc;
- static int first_option = 1;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'N':
- nmt_system = atoi(optarg);
- if (nmt_system != 450 && nmt_system != 900) {
- fprintf(stderr, "Error, NMT system type '%s' unknown. Please use '-N 450' for NMT-450 or '-N 900' for NMT-900.\n", optarg);
- exit(0);
- }
- if (nmt_system == 900)
- ms_power = 0;
- if (!first_option) {
- fprintf(stderr, "Please specify the NMT system (-N) as first command line option!\n");
- exit(0);
- }
- skip_args += 2;
- break;
- case 'T':
- if (!strcmp(optarg, "list")) {
- nmt_channel_list(nmt_system);
- exit(0);
- }
- rc = nmt_channel_by_short_name(nmt_system, optarg);
- if (rc < 0) {
- fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg);
- exit(0);
- }
- OPT_ARRAY(num_chan_type, chan_type, rc)
- skip_args += 2;
- break;
- case 'P':
- ms_power = atoi(optarg);
- if (ms_power > 3)
- ms_power = 3;
- if (ms_power < 0)
- ms_power = 0;
- skip_args += 2;
- break;
- case 'Y':
-
- if (!strcmp(optarg, "list")) {
- nmt_country_list(nmt_system);
- exit(0);
- }
- /* digits */
- strncpy(country, optarg, sizeof(country) - 1);
- country[sizeof(country) - 1] = '\0';
- p = strchr(country, ',');
- if (!p) {
- fprintf(stderr, "Illegal traffic area '%s', see '-h' for help\n", optarg);
- exit(0);
- }
- *p++ = '\0';
- rc = nmt_country_by_short_name(nmt_system, country);
- if (rc < 0) {
+
+ switch (short_option) {
+ case 'N':
+ nmt_system = atoi(argv[argi]);
+ if (nmt_system != 450 && nmt_system != 900) {
+ fprintf(stderr, "Error, NMT system type '%s' unknown. Please use '-N 450' for NMT-450 or '-N 900' for NMT-900.\n", argv[argi]);
+ return -EINVAL;
+ }
+ if (nmt_system == 900)
+ ms_power = 0;
+ if (!option_is_first()) {
+ fprintf(stderr, "Please specify the NMT system (-N) as first command line option!\n");
+ return -EINVAL;
+ }
+ break;
+ case 'T':
+ if (!strcmp(argv[argi], "list")) {
+ nmt_channel_list(nmt_system);
+ return 0;
+ }
+ rc = nmt_channel_by_short_name(nmt_system, argv[argi]);
+ if (rc < 0) {
+ fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]);
+ return -EINVAL;
+ }
+ OPT_ARRAY(num_chan_type, chan_type, rc)
+ break;
+ case 'P':
+ ms_power = atoi(argv[argi]);
+ if (ms_power > 3)
+ ms_power = 3;
+ if (ms_power < 0)
+ ms_power = 0;
+ break;
+ case 'Y':
+
+ if (!strcmp(argv[argi], "list")) {
+ nmt_country_list(nmt_system);
+ return 0;
+ }
+ /* digits */
+ strncpy(country, argv[argi], sizeof(country) - 1);
+ country[sizeof(country) - 1] = '\0';
+ p = strchr(country, ',');
+ if (!p) {
+ fprintf(stderr, "Illegal traffic area '%s', see '-h' for help\n", argv[argi]);
+ return -EINVAL;
+ }
+ *p++ = '\0';
+ rc = nmt_country_by_short_name(nmt_system, country);
+ if (rc < 0) {
error_ta:
- fprintf(stderr, "Invalid traffic area '%s', use '-Y list' for a list of valid areas\n", optarg);
- exit(0);
- }
- traffic_area[0] = rc + '0';
- if (p[strlen(p) - 1] != '!') {
- rc = nmt_ta_by_short_name(nmt_system, country, atoi(p));
- if (rc < 0)
- goto error_ta;
- }
- nmt_value2digits(atoi(p), traffic_area + 1, 1);
- traffic_area[2] = '\0';
- skip_args += 2;
- break;
- case 'A':
- area_no = optarg[0] - '0';
- if (area_no > 4) {
- fprintf(stderr, "Area number '%s' out of range, please use 1..4 or 0 for no area\n", optarg);
- exit(0);
- }
- skip_args += 2;
- break;
- case 'C':
- compandor = atoi(optarg);
- skip_args += 2;
- break;
- case '0':
- super = atoi(optarg);
- if (super < 0 || super > 4) {
- fprintf(stderr, "Given supervisory signal is wrong, use '-h' for help!\n");
- exit(0);
- }
- OPT_ARRAY(num_supervisory, supervisory, super)
- skip_args += 2;
- break;
- case 'S':
- smsc_number = strdup(optarg);
- skip_args += 2;
- break;
- case 'I':
- send_callerid = atoi(optarg);
- skip_args += 2;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ fprintf(stderr, "Invalid traffic area '%s', use '-Y list' for a list of valid areas\n", argv[argi]);
+ return -EINVAL;
+ }
+ traffic_area[0] = rc + '0';
+ if (p[strlen(p) - 1] != '!') {
+ rc = nmt_ta_by_short_name(nmt_system, country, atoi(p));
+ if (rc < 0)
+ goto error_ta;
+ }
+ nmt_value2digits(atoi(p), traffic_area + 1, 1);
+ traffic_area[2] = '\0';
+ break;
+ case 'A':
+ area_no = argv[argi][0] - '0';
+ if (area_no > 4) {
+ fprintf(stderr, "Area number '%s' out of range, please use 1..4 or 0 for no area\n", argv[argi]);
+ return -EINVAL;
+ }
+ break;
+ case 'C':
+ compandor = atoi(argv[argi]);
+ break;
+ case '0':
+ super = atoi(argv[argi]);
+ if (super < 0 || super > 4) {
+ fprintf(stderr, "Given supervisory signal is wrong, use '-h' for help!\n");
+ return -EINVAL;
}
- first_option = 0;
+ OPT_ARRAY(num_supervisory, supervisory, super)
+ break;
+ case 'S':
+ smsc_number = strdup(argv[argi]);
+ break;
+ case 'I':
+ send_callerid = atoi(argv[argi]);
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- free(long_options);
-
- return skip_args;
+ return 1;
}
static void myhandler(void)
@@ -280,8 +258,7 @@ int submit_sms(const char *sms)
int main(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int mandatory = 0;
int i;
@@ -292,12 +269,17 @@ int main(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/nmt.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 7) {
printf("Given station ID '%s' does not have 7 digits\n", station_id);
return 0;
@@ -338,7 +320,7 @@ int main(int argc, char *argv[])
num_audiodev = 1; /* use default */
if (num_kanal != num_audiodev) {
fprintf(stderr, "You need to specify as many sound devices as you have channels.\n");
- exit(0);
+ return -EINVAL;
}
if (num_kanal == 1 && num_chan_type == 0) {
num_chan_type = 1; /* use default */
@@ -347,14 +329,14 @@ int main(int argc, char *argv[])
}
if (num_kanal != num_chan_type) {
fprintf(stderr, "You need to specify as many channel types as you have channels.\n");
- exit(0);
+ return -EINVAL;
}
if (num_kanal == 1 && num_supervisory == 0)
num_supervisory = 1; /* use default */
if (num_kanal != num_supervisory) {
fprintf(stderr, "You need to specify as many supervisory signals as you have channels.\n");
fprintf(stderr, "They shall be different at channels that are close to each other.\n");
- exit(0);
+ return -EINVAL;
}
if (num_kanal) {
uint8_t super[5] = { 0, 0, 0, 0, 0 };
@@ -378,7 +360,7 @@ int main(int argc, char *argv[])
}
if (mandatory) {
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
diff --git a/src/r2000/Makefile.am b/src/r2000/Makefile.am
index 9500a2c..120221b 100644
--- a/src/r2000/Makefile.am
+++ b/src/r2000/Makefile.am
@@ -12,6 +12,7 @@ radiocom2000_SOURCES = \
main.c
radiocom2000_LDADD = \
$(COMMON_LA) \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/r2000/main.c b/src/r2000/main.c
index c772d75..bf4e98f 100644
--- a/src/r2000/main.c
+++ b/src/r2000/main.c
@@ -19,16 +19,17 @@
#include <stdio.h>
#include <stdint.h>
-#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "../libsample/sample.h"
#include "../libmobile/main_mobile.h"
#include "../libdebug/debug.h"
+#include "../liboptions/options.h"
#include "r2000.h"
#include "dsp.h"
#include "frame.h"
@@ -102,179 +103,154 @@ void print_help(const char *arg0)
#define OPT_TAXE 258
#define OPT_DESTRUCTION 259
-static int handle_options(int argc, char **argv)
+static void add_options(void)
{
- int skip_args = 0;
-
- static struct option long_options_special[] = {
- {"band", 1, 0, 'B'},
- {"bande", 1, 0, OPT_BANDE},
- {"channel-type", 1, 0, 'T'},
- {"relais", 1, 0, 'R'},
- {"deport", 1, 0, OPT_DEPORT},
- {"agi", 1, 0, 'I'},
- {"sm-power", 1, 0, 'P'},
- {"taxe", 1, 0, OPT_TAXE},
- {"crins", 1, 0, 'C'},
- {"destruction", 1, 0, OPT_DESTRUCTION},
- {"nconv", 1, 0, 'N'},
- {"recall", 1, 0, 'S'},
- {0, 0, 0, 0}
- };
-
- main_mobile_set_options("B:T:R:I:P:C:N:S", long_options_special);
-
- while (1) {
- int option_index = 0, c, rc;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
+ main_mobile_add_options();
+ option_add('B', "band", 1);
+ option_add(OPT_BANDE, "bande", 1);
+ option_add('T', "channel-type", 1);
+ option_add('R', "relais", 1);
+ option_add(OPT_DEPORT, "deport", 1);
+ option_add('I', "agi", 1);
+ option_add('P', "sm-power", 1);
+ option_add(OPT_TAXE, "taxe", 1);
+ option_add('C', "crins", 1);
+ option_add(OPT_DESTRUCTION, "destruction", 1);
+ option_add('N', "nconv", 1);
+ option_add('S', "recall", 1);
+}
- switch (c) {
- case 'B':
- case OPT_BANDE:
- if (!strcmp(optarg, "list")) {
- r2000_band_list();
- exit(0);
- }
- band = atoi(optarg);
- skip_args += 2;
- break;
- case 'T':
- if (!strcmp(optarg, "list")) {
- r2000_channel_list();
- exit(0);
- }
- rc = r2000_channel_by_short_name(optarg);
- if (rc < 0) {
- fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg);
- exit(0);
- }
- OPT_ARRAY(num_chan_type, chan_type, rc)
- skip_args += 2;
- break;
- case 'R':
- relais = atoi(optarg);
- if (relais > 511)
- relais = 511;
- if (relais < 1)
- relais = 1;
- skip_args += 2;
- break;
- case OPT_DEPORT:
- deport = atoi(optarg);
- if (deport > 7)
- deport = 7;
- if (deport < 0)
- deport = 0;
- skip_args += 2;
- break;
- case 'I':
- if (!strcmp(optarg, "list")) {
- int i;
+static int handle_options(int short_option, int argi, char **argv)
+{
+ int rc;
- printf("\nList of possible AGI (inscription permission) codes:\n\n");
- printf("Value\tDescription\n");
- printf("------------------------------------------------------------------------\n");
- for (i = 0; i < 8; i++)
- printf("%d\t%s\n", i, param_agi(i));
- exit(0);
- }
- agi = atoi(optarg);
- if (agi < 0 || agi > 7) {
- fprintf(stderr, "Error, given inscription permission (AGI) %d is invalid, use 'list' to get a list of values!\n", agi);
- exit(0);
- }
- skip_args += 2;
- break;
- case 'P':
- sm_power = atoi(optarg);
- if (sm_power > 1)
- sm_power = 1;
- if (sm_power < 0)
- sm_power = 0;
- skip_args += 2;
- break;
- case OPT_TAXE:
- taxe = atoi(optarg);
- if (taxe > 1)
- taxe = 1;
- if (taxe < 0)
- taxe = 0;
- skip_args += 2;
- break;
+ switch (short_option) {
+ case 'B':
+ case OPT_BANDE:
+ if (!strcmp(argv[argi], "list")) {
+ r2000_band_list();
+ return 0;
+ }
+ band = atoi(argv[argi]);
+ break;
+ case 'T':
+ if (!strcmp(argv[argi], "list")) {
+ r2000_channel_list();
+ return 0;
+ }
+ rc = r2000_channel_by_short_name(argv[argi]);
+ if (rc < 0) {
+ fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", argv[argi]);
+ return -EINVAL;
+ }
+ OPT_ARRAY(num_chan_type, chan_type, rc)
+ break;
+ case 'R':
+ relais = atoi(argv[argi]);
+ if (relais > 511)
+ relais = 511;
+ if (relais < 1)
+ relais = 1;
+ break;
+ case OPT_DEPORT:
+ deport = atoi(argv[argi]);
+ if (deport > 7)
+ deport = 7;
+ if (deport < 0)
+ deport = 0;
+ break;
+ case 'I':
+ if (!strcmp(argv[argi], "list")) {
+ int i;
+
+ printf("\nList of possible AGI (inscription permission) codes:\n\n");
+ printf("Value\tDescription\n");
+ printf("------------------------------------------------------------------------\n");
+ for (i = 0; i < 8; i++)
+ printf("%d\t%s\n", i, param_agi(i));
+ return 0;
+ }
+ agi = atoi(argv[argi]);
+ if (agi < 0 || agi > 7) {
+ fprintf(stderr, "Error, given inscription permission (AGI) %d is invalid, use 'list' to get a list of values!\n", agi);
+ return -EINVAL;
+ }
+ break;
+ case 'P':
+ sm_power = atoi(argv[argi]);
+ if (sm_power > 1)
+ sm_power = 1;
+ if (sm_power < 0)
+ sm_power = 0;
+ break;
+ case OPT_TAXE:
+ taxe = atoi(argv[argi]);
+ if (taxe > 1)
+ taxe = 1;
+ if (taxe < 0)
+ taxe = 0;
+ break;
#if 0
- case 'A':
- if (!strcmp(optarg, "list")) {
- int i;
-
- printf("\nList of possible AGA (call permission) codes:\n\n");
- printf("Value\tDescription\n");
- printf("------------------------------------------------------------------------\n");
- for (i = 0; i < 4; i++)
- printf("%d\t%s\n", i, param_aga(i));
- exit(0);
- }
- aga = atoi(optarg);
- if (aga < 0 || aga > 3) {
- fprintf(stderr, "Error, given call permission (AGA) %d is invalid, use 'list' to get a list of values!\n", aga);
- exit(0);
- }
- skip_args += 2;
- break;
+ case 'A':
+ if (!strcmp(argv[argi], "list")) {
+ int i;
+
+ printf("\nList of possible AGA (call permission) codes:\n\n");
+ printf("Value\tDescription\n");
+ printf("------------------------------------------------------------------------\n");
+ for (i = 0; i < 4; i++)
+ printf("%d\t%s\n", i, param_aga(i));
+ return 0;
+ }
+ aga = atoi(argv[argi]);
+ if (aga < 0 || aga > 3) {
+ fprintf(stderr, "Error, given call permission (AGA) %d is invalid, use 'list' to get a list of values!\n", aga);
+ return -EINVAL;
+ }
+ break;
#endif
- case 'C':
- if (!strcmp(optarg, "list")) {
- int i;
-
- printf("\nList of possible CRINS (inscription response) codes:\n\n");
- printf("Value\tDescription\n");
- printf("------------------------------------------------------------------------\n");
- for (i = 0; i < 8; i++)
- printf("%d\t%s\n", i, param_crins(i));
- exit(0);
- }
- crins = atoi(optarg);
- if (crins < 0 || crins > 7) {
- fprintf(stderr, "Error, given inscription response (CRINS) %d is invalid, use 'list' to get a list of values!\n", crins);
- exit(0);
- }
- skip_args += 2;
- break;
- case OPT_DESTRUCTION:
- if (!strcmp(optarg, "YES")) {
- destruction = 2342;
- }
- skip_args += 2;
- break;
- case 'N':
- nconv = atoi(optarg);
- if (nconv > 7)
- nconv = 7;
- if (nconv < 0)
- nconv = 0;
- skip_args += 2;
- break;
- case 'S':
- recall = 1;
- skip_args += 1;
- break;
- default:
- main_mobile_opt_switch(c, argv[0], &skip_args);
+ case 'C':
+ if (!strcmp(argv[argi], "list")) {
+ int i;
+
+ printf("\nList of possible CRINS (inscription response) codes:\n\n");
+ printf("Value\tDescription\n");
+ printf("------------------------------------------------------------------------\n");
+ for (i = 0; i < 8; i++)
+ printf("%d\t%s\n", i, param_crins(i));
+ return 0;
+ }
+ crins = atoi(argv[argi]);
+ if (crins < 0 || crins > 7) {
+ fprintf(stderr, "Error, given inscription response (CRINS) %d is invalid, use 'list' to get a list of values!\n", crins);
+ return -EINVAL;
+ }
+ break;
+ case OPT_DESTRUCTION:
+ if (!strcmp(argv[argi], "YES")) {
+ destruction = 2342;
}
+ break;
+ case 'N':
+ nconv = atoi(argv[argi]);
+ if (nconv > 7)
+ nconv = 7;
+ if (nconv < 0)
+ nconv = 0;
+ break;
+ case 'S':
+ recall = 1;
+ break;
+ default:
+ return main_mobile_handle_options(short_option, argi, argv);
}
- free(long_options);
-
- return skip_args;
+ return 1;
}
int main(int argc, char *argv[])
{
- int rc;
- int skip_args;
+ int rc, argi;
const char *station_id = "";
int mandatory = 0;
int i;
@@ -284,12 +260,17 @@ int main(int argc, char *argv[])
main_mobile_init();
- skip_args = handle_options(argc, argv);
- argc -= skip_args;
- argv += skip_args;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/radiocom2000.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
- if (argc > 1) {
- station_id = argv[1];
+ if (argi < argc) {
+ station_id = argv[argi];
if (strlen(station_id) != 9) {
printf("Given station ID '%s' does not have 9 digits\n", station_id);
return 0;
@@ -328,7 +309,7 @@ int main(int argc, char *argv[])
}
if (mandatory) {
- print_help(argv[-skip_args]);
+ print_help(argv[0]);
return 0;
}
diff --git a/src/radio/Makefile.am b/src/radio/Makefile.am
index 24c65da..a96e3bb 100644
--- a/src/radio/Makefile.am
+++ b/src/radio/Makefile.am
@@ -10,6 +10,7 @@ osmoradio_SOURCES = \
main.c
osmoradio_LDADD = \
$(COMMON_LA) \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libwave/libwave.a \
$(top_builddir)/src/libsample/libsample.a \
diff --git a/src/radio/main.c b/src/radio/main.c
index d576ffe..77c415b 100644
--- a/src/radio/main.c
+++ b/src/radio/main.c
@@ -1,4 +1,4 @@
-/* main function
+/* Radio main function
*
* (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
@@ -24,8 +24,8 @@ enum paging_signal;
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
-#include <getopt.h>
#include <signal.h>
+#include <errno.h>
#include <math.h>
#include <termios.h>
#include <unistd.h>
@@ -34,6 +34,7 @@ enum paging_signal;
#include "../libsdr/sdr_config.h"
#include "../libsdr/sdr.h"
#include "../libdisplay/display.h"
+#include "../liboptions/options.h"
#include "radio.h"
#define DEFAULT_LO_OFFSET -1000000.0
@@ -137,170 +138,121 @@ void print_help(const char *arg0)
printf(" -S --stereo\n");
printf(" Enables stereo carrier for frequency modulated UHF broadcast.\n");
printf(" It uses the 'Pilot-tone' system.\n");
+ printf(" --limesdr\n");
+ printf(" Auto-select several required options for LimeSDR\n");
sdr_config_print_help();
}
-static struct option long_options_common[] = {
- {"help", 0, 0, 'h'},
- {"frequency", 1, 0, 'f'},
- {"samplerate", 1, 0, 's'},
- {"tx-wave-file", 1, 0, 'r'},
- {"rx-wave-file", 1, 0, 'w'},
- {"audio-device", 1, 0, 'a'},
- {"modulation", 1, 0, 'M'},
- {"rx", 0, 0, 'R'},
- {"tx", 0, 0, 'T'},
- {"bandwidth", 1, 0, 'B'},
- {"deviation", 1, 0, 'D'},
- {"modulation-index", 1, 0, 'I'},
- {"emphasis", 1, 0, 'E'},
- {"stereo", 0, 0, 'S'},
- {0, 0, 0, 0}
-};
-
-static const char *optstring_common = "hf:s:r:w:a:M:RTB:D:I:E:S";
-
-struct option *long_options;
-char *optstring;
-
-static void check_duplicate_option(int num, struct option *option)
-{
- int i;
+#define OPT_LIMESDR 1100
- 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 set_options_common(void)
+static void add_options(void)
{
- int i = 0, j;
-
- long_options = calloc(sizeof(*long_options), 256);
- for (j = 0; long_options_common[i].name; i++, j++) {
- check_duplicate_option(i, &long_options_common[j]);
- memcpy(&long_options[i], &long_options_common[j], sizeof(*long_options));
- }
- 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));
- }
-
- optstring = calloc(256, 2);
- strcpy(optstring, optstring_common);
- strcat(optstring, sdr_config_optstring);
+ option_add('h', "help", 0);
+ option_add('f', "frequency", 1);
+ option_add('s', "samplerate", 1);
+ option_add('r', "tx-wave-file", 1);
+ option_add('w', "rx-wave-file", 1);
+ option_add('a', "audio-device", 1);
+ option_add('M', "modulation", 1);
+ option_add('R', "rx", 0);
+ option_add('T', "tx", 0);
+ option_add('B', "bandwidth", 1);
+ option_add('D', "deviation", 1);
+ option_add('I', "modulation-index", 1);
+ option_add('E', "emphasis", 1);
+ option_add('S', "stereo", 0);
+ option_add(OPT_LIMESDR, "limesdr", 0);
+ sdr_config_add_options();
}
-static int handle_options(int argc, char **argv)
+static int handle_options(int short_option, int argi, char **argv)
{
- int skip_args = 0;
- int rc;
-
- set_options_common();
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_help(argv[0]);
- exit(0);
- case 'f':
- frequency = atof(optarg);
- skip_args += 2;
- break;
- case 's':
- samplerate = atof(optarg);
- skip_args += 2;
- break;
- case 'r':
- tx_wave_file = strdup(optarg);
- skip_args += 2;
- break;
- case 'w':
- rx_wave_file = strdup(optarg);
- skip_args += 2;
- break;
- case 'a':
- tx_audiodev = strdup(optarg);
- rx_audiodev = strdup(optarg);
- skip_args += 2;
- break;
- case 'M':
- if (!strcasecmp(optarg, "fm"))
- modulation = MODULATION_FM;
- else
- if (!strcasecmp(optarg, "am"))
- modulation = MODULATION_AM_DSB;
- else
- if (!strcasecmp(optarg, "usb"))
- modulation = MODULATION_AM_USB;
- else
- if (!strcasecmp(optarg, "lsb"))
- modulation = MODULATION_AM_LSB;
- else
- {
- fprintf(stderr, "Invalid modulation option, see help!\n");
- exit(0);
- }
- skip_args += 2;
- break;
- case 'R':
- rx = 1;
- skip_args += 1;
- break;
- case 'T':
- tx = 1;
- skip_args += 1;
- break;
- case 'B':
- bandwidth = atof(optarg);
- skip_args += 2;
- break;
- case 'D':
- deviation = atof(optarg);
- skip_args += 2;
- break;
- case 'I':
- modulation_index = atof(optarg);
- if (modulation_index < 0.0 || modulation_index > 1.0) {
- fprintf(stderr, "Invalid modulation index, see help!\n");
- exit(0);
- }
- skip_args += 2;
- break;
- case 'E':
- time_constant_us = atof(optarg);
- skip_args += 2;
- break;
- case 'S':
- stereo = 1;
- skip_args += 1;
- break;
- default:
- rc = sdr_config_opt_switch(c, &skip_args);
- if (rc < 0)
- exit(0);
- break;
+ switch (short_option) {
+ case 'h':
+ print_help(argv[0]);
+ return 0;
+ case 'f':
+ frequency = atof(argv[argi]);
+ break;
+ case 's':
+ samplerate = atof(argv[argi]);
+ break;
+ case 'r':
+ tx_wave_file = strdup(argv[argi]);
+ break;
+ case 'w':
+ rx_wave_file = strdup(argv[argi]);
+ break;
+ case 'a':
+ tx_audiodev = strdup(argv[argi]);
+ rx_audiodev = strdup(argv[argi]);
+ break;
+ case 'M':
+ if (!strcasecmp(argv[argi], "fm"))
+ modulation = MODULATION_FM;
+ else
+ if (!strcasecmp(argv[argi], "am"))
+ modulation = MODULATION_AM_DSB;
+ else
+ if (!strcasecmp(argv[argi], "usb"))
+ modulation = MODULATION_AM_USB;
+ else
+ if (!strcasecmp(argv[argi], "lsb"))
+ modulation = MODULATION_AM_LSB;
+ else
+ {
+ fprintf(stderr, "Invalid modulation option, use '-h' for help!\n");
+ return -EINVAL;
}
+ break;
+ case 'R':
+ rx = 1;
+ break;
+ case 'T':
+ tx = 1;
+ break;
+ case 'B':
+ bandwidth = atof(argv[argi]);
+ break;
+ case 'D':
+ deviation = atof(argv[argi]);
+ break;
+ case 'I':
+ modulation_index = atof(argv[argi]);
+ if (modulation_index < 0.0 || modulation_index > 1.0) {
+ fprintf(stderr, "Invalid modulation index, use '-h' for help!\n");
+ return -EINVAL;
+ }
+ break;
+ case 'E':
+ time_constant_us = atof(argv[argi]);
+ break;
+ case 'S':
+ stereo = 1;
+ break;
+ case OPT_LIMESDR:
+ {
+ char *argv_lime[] = { argv[0],
+ "--sdr-soapy",
+ "--sdr-rx-antenna", "LNAL",
+ "--sdr-rx-gain", "50",
+ "--sdr-tx-gain", "50",
+ "--sdr-samplerate", "5000000",
+ "--sdr-bandwidth", "15000000",
+ };
+ int argc_lime = sizeof(argv_lime) / sizeof (*argv_lime);
+ return options_command_line(argc_lime, argv_lime, handle_options);
+ }
+ default:
+ return sdr_config_handle_options(short_option, argi, argv);
}
- return skip_args;
+ return 1;
}
int main(int argc, char *argv[])
{
- int skip_args;
- int rc;
- const char *arg0 = argv[0];
+ int rc, argi;
radio_t radio;
struct termios term, term_orig;
int c;
@@ -310,13 +262,18 @@ int main(int argc, char *argv[])
sdr_config_init(DEFAULT_LO_OFFSET);
- skip_args = handle_options(argc, argv);
- argc -= skip_args + 1;
- argv += skip_args + 1;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/radio.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
if (frequency == 0.0) {
printf("No frequency given, I suggest to use 100000000 (100 MHz) and FM\n\n");
- print_help(arg0);
+ print_help(argv[0]);
exit(0);
}
@@ -324,12 +281,12 @@ int main(int argc, char *argv[])
if (rc < 0)
return rc;
if (rc == 0) {
- fprintf(stderr, "Please select SDR, see help!\n");
+ fprintf(stderr, "Please select SDR, use '-h' for help!\n");
exit(0);
}
if (modulation == MODULATION_NONE) {
- fprintf(stderr, "Please select modulation, see help!\n");
+ fprintf(stderr, "Please select modulation, use '-h' for help!\n");
exit(0);
}
@@ -341,18 +298,18 @@ int main(int argc, char *argv[])
}
if (stereo && modulation != MODULATION_FM) {
- fprintf(stderr, "Stereo works with FM only, see help!\n");
+ fprintf(stderr, "Stereo works with FM only, use '-h' for help!\n");
exit(0);
}
if (!rx && !tx) {
- fprintf(stderr, "You need to specify --rx (receiver) and/or --tx (transmitter), see help!\n");
+ fprintf(stderr, "You need to specify --rx (receiver) and/or --tx (transmitter), use '-h' for help!\n");
exit(0);
}
if (stereo && bandwidth != 15000.0) {
fprintf(stderr, "Warning: Stereo works with bandwidth of 15 KHz only, using this bandwidth!\n");
}
if (stereo && time_constant_us != 75.0 && time_constant_us != 50.0) {
- fprintf(stderr, "Stereo works with time constant of 50 uS or 75 uS only, see help!\n");
+ fprintf(stderr, "Stereo works with time constant of 50 uS or 75 uS only, use '-h' for help!\n");
exit(0);
}
diff --git a/src/tacs/Makefile.am b/src/tacs/Makefile.am
index ec9b593..5a0a894 100644
--- a/src/tacs/Makefile.am
+++ b/src/tacs/Makefile.am
@@ -13,6 +13,7 @@ tacs_SOURCES = \
tacs_LDADD = \
$(COMMON_LA) \
../amps/libamps.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 5f7a86e..141d88d 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -57,6 +57,7 @@ test_dms_LDADD = \
$(COMMON_LA) \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/nmt/libdmssms.a \
$(top_builddir)/src/libjitter/libjitter.a \
@@ -90,6 +91,7 @@ test_sms_LDADD = \
$(COMMON_LA) \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdisplay/libdisplay.a \
$(top_builddir)/src/nmt/libdmssms.a \
$(top_builddir)/src/libjitter/libjitter.a \
diff --git a/src/test/test_dms.c b/src/test/test_dms.c
index 1d3492f..5a29543 100644
--- a/src/test/test_dms.c
+++ b/src/test/test_dms.c
@@ -43,7 +43,7 @@ void dms_receive(nmt_t *nmt, const uint8_t *data, int length, int eight_bits)
{
printf("(getting %d digits from DMS layer)\n", length);
- assert(!memcmp((const char *)data, check_sequence, length), "Expecting received data to macht");
+ assert(!memcmp((const char *)data, check_sequence, length), "Expecting received data to match");
check_sequence += length;
check_length = length;
diff --git a/src/tv/Makefile.am b/src/tv/Makefile.am
index 733541a..d1fdb37 100644
--- a/src/tv/Makefile.am
+++ b/src/tv/Makefile.am
@@ -14,6 +14,7 @@ osmotv_SOURCES = \
main.c
osmotv_LDADD = \
$(COMMON_LA) \
+ $(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libimage/libimage.a \
$(top_builddir)/src/libfm/libfm.a \
diff --git a/src/tv/main.c b/src/tv/main.c
index 01b27f0..7331c1d 100644
--- a/src/tv/main.c
+++ b/src/tv/main.c
@@ -1,4 +1,4 @@
-/* main function
+/* JollyTV main function
*
* (C) 2017 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
@@ -24,8 +24,8 @@ enum paging_signal;
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
-#include <getopt.h>
#include <signal.h>
+#include <errno.h>
#include <math.h>
#include "../libsample/sample.h"
#include "../libfilter/iir_filter.h"
@@ -37,6 +37,7 @@ enum paging_signal;
#include "../libsdr/sdr_config.h"
#include "../libsdr/sdr.h"
#endif
+#include "../liboptions/options.h"
#include "bas.h"
#include "tv_modulate.h"
#include "channels.h"
@@ -114,149 +115,104 @@ void print_help(const char *arg0)
printf(" Give exactly 12 characters to display as Station ID.\n");
printf(" (default = \"%s\")\n", station_id);
#ifdef HAVE_SDR
+ printf(" --limesdr\n");
+ printf(" Auto-select several required options for LimeSDR\n");
sdr_config_print_help();
#endif
}
-static struct option long_options_common[] = {
- {"help", 0, 0, 'h'},
- {"frequency", 1, 0, 'f'},
- {"channel", 1, 0, 'c'},
- {"samplerate", 1, 0, 'r'},
- {"wave-file", 1, 0, 'w'},
- {"fbas", 1, 0, 'F'},
- {"tone", 1, 0, 'T'},
- {"circle-radius", 1, 0, 'R'},
- {"color-bar", 1, 0, 'C'},
- {"grid-only", 1, 0, 'G'},
- {"station-id", 1, 0, 'I'},
- {0, 0, 0, 0}
-};
-
-static const char *optstring_common = "hf:c:r:w:F:T:R:C:G:I:";
-
-struct option *long_options;
-char *optstring;
-
-static void check_duplicate_option(int num, struct option *option)
-{
- int i;
+#define OPT_LIMESDR 1100
- 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 set_options_common(void)
+static void add_options(void)
{
- int i = 0, j;
-
- long_options = calloc(sizeof(*long_options), 256);
- for (j = 0; long_options_common[i].name; i++, j++) {
- check_duplicate_option(i, &long_options_common[j]);
- memcpy(&long_options[i], &long_options_common[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
-
- optstring = calloc(256, 2);
- strcpy(optstring, optstring_common);
+ option_add('h', "help", 0);
+ option_add('f', "frequency", 1);
+ option_add('c', "channel", 1);
+ option_add('r', "samplerate", 1);
+ option_add('w', "wave-file", 1);
+ option_add('F', "fbas", 1);
+ option_add('T', "tone", 1);
+ option_add('R', "circle-radius", 1);
+ option_add('C', "color-bar", 1);
+ option_add('G', "grid-only", 1);
+ option_add('I', "station-id", 1);
#ifdef HAVE_SDR
- strcat(optstring, sdr_config_optstring);
+ option_add(OPT_LIMESDR, "limesdr", 0);
+ sdr_config_add_options();
#endif
}
-static int handle_options(int argc, char **argv)
+static int handle_options(int short_option, int argi, char **argv)
{
- int skip_args = 0;
+ switch (short_option) {
+ case 'h':
+ print_help(argv[0]);
+ return 0;
+ case 'f':
+ frequency = atof(argv[argi]);
+ break;
+ case 'c':
+ if (!strcmp(argv[argi], "list")) {
+ list_tv_channels();
+ return 0;
+ }
+ frequency = get_tv_video_frequency(atoi(argv[argi]));
+ if (frequency == 0.0) {
+ fprintf(stderr, "Given channel number unknown, use \"-c list\" to get a list.\n");
+ return -EINVAL;
+ }
+ break;
+ case 'r':
+ samplerate = atof(argv[argi]);
+ break;
+ case 'w':
+ wave_file = strdup(argv[argi]);
+ break;
+ case 'F':
+ fbas = atoi(argv[argi]);
+ break;
+ case 'T':
+ tone = atoi(argv[argi]);
+ break;
+ case 'R':
+ circle_radius = atof(argv[argi]);
+ break;
+ case 'C':
+ color_bar = atoi(argv[argi]);
+ break;
+ case 'G':
+ grid_only = atoi(argv[argi]);
+ break;
+ case 'I':
+ station_id = strdup(argv[argi]);
+ if (strlen(station_id) != 12) {
+ fprintf(stderr, "Given station ID must be exactly 12 charaters long. (Use spaces to fill it.)\n");
+ return -EINVAL;
+ }
+ break;
#ifdef HAVE_SDR
- int rc;
+ case OPT_LIMESDR:
+ {
+ char *argv_lime[] = { argv[0],
+ "--sdr-soapy",
+ "--sdr-tx-gain", "50",
+ "--sdr-lo-offset", "-3000000",
+ "--sdr-bandwidth", "60000000",
+ "-r", "13750000",
+ };
+ int argc_lime = sizeof(argv_lime) / sizeof (*argv_lime);
+ return options_command_line(argc_lime, argv_lime, handle_options);
+ }
#endif
-
- set_options_common();
-
- while (1) {
- int option_index = 0, c;
-
- c = getopt_long(argc, argv, optstring, long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_help(argv[0]);
- exit(0);
- case 'f':
- frequency = atof(optarg);
- skip_args += 2;
- break;
- case 'c':
- if (!strcmp(optarg, "list")) {
- list_tv_channels();
- exit(0);
- }
- frequency = get_tv_video_frequency(atoi(optarg));
- if (frequency == 0.0) {
- fprintf(stderr, "Given channel number unknown, use \"-c list\" to get a list.\n");
- exit(0);
- }
- skip_args += 2;
- break;
- case 'r':
- samplerate = atof(optarg);
- skip_args += 2;
- break;
- case 'w':
- wave_file = strdup(optarg);
- skip_args += 2;
- break;
- case 'F':
- fbas = atoi(optarg);
- skip_args += 2;
- break;
- case 'T':
- tone = atoi(optarg);
- skip_args += 2;
- break;
- case 'R':
- circle_radius = atof(optarg);
- skip_args += 2;
- break;
- case 'C':
- color_bar = atoi(optarg);
- skip_args += 2;
- break;
- case 'G':
- grid_only = atoi(optarg);
- skip_args += 2;
- break;
- case 'I':
- station_id = strdup(optarg);
- if (strlen(station_id) != 12) {
- fprintf(stderr, "Given station ID must be exactly 12 charaters long. (Use spaces to fill it.)\n");
- exit(0);
- }
- skip_args += 2;
- break;
- default:
+ default:
#ifdef HAVE_SDR
- rc = sdr_config_opt_switch(c, &skip_args);
- if (rc < 0)
- exit(0);
+ return sdr_config_handle_options(short_option, argi, argv);
+#else
+ return -EINVAL;
#endif
- break;
- }
}
- return skip_args;
+ return 1;
}
static void tx_bas(sample_t *sample_bas, __attribute__((__unused__)) sample_t *sample_tone, __attribute__((__unused__)) uint8_t *power_tone, int samples)
@@ -448,9 +404,7 @@ error:
int main(int argc, char *argv[])
{
- int skip_args;
- int __attribute__((__unused__)) rc;
- const char *arg0 = argv[0];
+ int __attribute__((__unused__)) rc, argi;
debuglevel = 0;
@@ -458,12 +412,17 @@ int main(int argc, char *argv[])
sdr_config_init(DEFAULT_LO_OFFSET);
#endif
- skip_args = handle_options(argc, argv);
- argc -= skip_args + 1;
- argv += skip_args + 1;
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/analog/osmotv.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
if (frequency == 0.0 && !wave_file) {
- print_help(arg0);
+ print_help(argv[0]);
exit(0);
}
@@ -475,22 +434,22 @@ int main(int argc, char *argv[])
#endif
}
- if (argc < 1) {
- fprintf(stderr, "Expecting command, see help!\n");
+ if (argi >= argc) {
+ fprintf(stderr, "Expecting command, use '-h' for help!\n");
exit(0);
- } else if (!strcmp(argv[0], "tx-fubk")) {
+ } else if (!strcmp(argv[argi], "tx-fubk")) {
tx_test_picture(BAS_FUBK);
- } else if (!strcmp(argv[0], "tx-vcr")) {
+ } else if (!strcmp(argv[argi], "tx-vcr")) {
tx_test_picture(BAS_VCR);
- } else if (!strcmp(argv[0], "tx-img")) {
- if (argc < 2) {
- fprintf(stderr, "Expecting image file, see help!\n");
- exit(0);
+ } else if (!strcmp(argv[argi], "tx-img")) {
+ if (argi + 1 >= argc) {
+ fprintf(stderr, "Expecting image file, use '-h' for help!\n");
+ return -EINVAL;
}
- tx_img(argv[1]);
+ tx_img(argv[argi + 1]);
} else {
- fprintf(stderr, "Unknown command '%s', see help!\n", argv[0]);
- exit(0);
+ fprintf(stderr, "Unknown command '%s', use '-h' for help!\n", argv[argi]);
+ return -EINVAL;
}
return 0;