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
This commit is contained in:
parent
e74b7442c6
commit
5df7f92647
|
@ -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" },
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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}
|
||||
void main_mobile_add_options(void)
|
||||
{
|
||||
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
|
||||
option_add(OPT_LIMESDR, "limesdr", 0);
|
||||
sdr_config_add_options();
|
||||
#endif
|
||||
};
|
||||
|
||||
static const char *main_mobile_optstring = "hv:k:a:s:i:b:pdg:exmc:t:l:r:";
|
||||
|
||||
struct option *long_options;
|
||||
char *optstring;
|
||||
|
||||
static void check_duplicate_option(int num, struct option *option)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (long_options[i].val == option->val) {
|
||||
fprintf(stderr, "Duplicate option %d. Please fix!\n", option->val);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main_mobile_set_options(const char *optstring_special, struct option *long_options_special)
|
||||
{
|
||||
int i = 0, j;
|
||||
|
||||
long_options = calloc(sizeof(*long_options), 256);
|
||||
for (j = 0; main_mobile_long_options[j].name; i++, j++) {
|
||||
check_duplicate_option(i, &main_mobile_long_options[j]);
|
||||
memcpy(&long_options[i], &main_mobile_long_options[j], sizeof(*long_options));
|
||||
}
|
||||
#ifdef HAVE_SDR
|
||||
for (j = 0; sdr_config_long_options[j].name; i++, j++) {
|
||||
check_duplicate_option(i, &sdr_config_long_options[j]);
|
||||
memcpy(&long_options[i], &sdr_config_long_options[j], sizeof(*long_options));
|
||||
}
|
||||
#endif
|
||||
for (; long_options_special->name; i++) {
|
||||
check_duplicate_option(i, long_options_special);
|
||||
memcpy(&long_options[i], long_options_special++, sizeof(*long_options));
|
||||
}
|
||||
|
||||
optstring = calloc(256, 2);
|
||||
strcpy(optstring, main_mobile_optstring);
|
||||
#ifdef HAVE_SDR
|
||||
strcat(optstring, sdr_config_optstring);
|
||||
#endif
|
||||
strcat(optstring, optstring_special);
|
||||
}
|
||||
|
||||
void print_help(const char *arg0);
|
||||
|
||||
void main_mobile_opt_switch(int c, char *arg0, int *skip_args)
|
||||
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 */
|
||||
|
|
|
@ -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) \
|
||||
{ \
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||
|
||||
noinst_LIBRARIES = liboptions.a
|
||||
|
||||
liboptions_a_SOURCES = \
|
||||
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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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>
|
||||
|
|
|
@ -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 = "";
|
||||
|
||||
int sdr_config_opt_switch(int c, int *skip_args)
|
||||
void sdr_config_add_options(void)
|
||||
{
|
||||
switch (c) {
|
||||
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_handle_options(int short_option, int argi, char **argv)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue