diff --git a/README.md b/README.md index d88846cb..1450bfa3 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,14 @@ bit to the side of the desired channel frequency, like this: ./dumpvdl2 --rtlsdr 0 --gain 40 --correction 42 --centerfreq 137100000 ``` +Frequencies might be specified in Hertz (as integer numbers) or in kHz, MHz, GHz +(as integer or floating-point numbers followed by any of the following suffixes: +k, K, m, M, g, G). + +``` +./dumpvdl2 --rtlsdr 0 --gain 40 --centerfreq 136M 136.725M 136975k 0.136875G +``` + ### Mirics Mirics is similar, however `libmirisdr-4` library currently lacks support for @@ -465,7 +473,7 @@ as an "expert mode" knob, which is hardly ever needed. Example 1: use SDRplay device ID=0, with auto gain and three VDL2 channels: ``` -./dumpvdl2 --sdrplay 0 136975000 136875000 136775000 +./dumpvdl2 --sdrplay 0 136.975M 136.875M 136.775M ``` Example 2: use SDRplay device with serial number 35830222, set gain reduction to @@ -473,7 +481,7 @@ Example 2: use SDRplay device with serial number 35830222, set gain reduction to frequency correction to -1ppm: ``` -./dumpvdl2 --sdrplay 35830222 --gr 40 --correction -1 --antenna A --biast 0 --notch-filter 1 136975000 +./dumpvdl2 --sdrplay 35830222 --gr 40 --correction -1 --antenna A --biast 0 --notch-filter 1 136.975M ``` ### SDRplay RSP native driver, version 3 @@ -1062,7 +1070,7 @@ dumpvdl2 --iq-file --centerfreq 136955000 136975000 Putting it all together: ``` -dumpvdl2 --iq-file iq.dat --sample-format S16_LE --oversample 13 --centerfreq 136955000 136975000 136725000 +dumpvdl2 --iq-file iq.dat --sample-format S16_LE --oversample 13 --centerfreq 136.955M 136.975M 136.725M ``` processes `iq.dat` file recorded at 1365000 samples/sec using 16-bit signed diff --git a/src/dumpvdl2.c b/src/dumpvdl2.c index eb310ebb..db18c68c 100644 --- a/src/dumpvdl2.c +++ b/src/dumpvdl2.c @@ -399,7 +399,7 @@ void usage() { describe_option("--debug ", "Debug message classes to display (default: none) (\"--debug help\" for details)", 1); #endif fprintf(stderr, "common options:\n"); - describe_option(" [ [...]]", "VDL2 channel frequencies, in Hz", 1); + describe_option(" [ [...]]", "VDL2 channel frequencies", 1); fprintf(stderr, "If channel frequencies are omitted, VDL2 Common Signalling Channel (%u Hz) will be used as default.\n\n", CSC_FREQ); #ifdef WITH_RTLSDR @@ -407,7 +407,7 @@ void usage() { describe_option("--rtlsdr ", "Use RTL device with specified ID or serial number (default: ID=0)", 1); describe_option("--gain ", "Set gain (decibels)", 1); describe_option("--correction ", "Set freq correction (ppm)", 1); - describe_option("--centerfreq ", "Set center frequency in Hz (default: auto)", 1); + describe_option("--centerfreq ", "Set center frequency (default: auto)", 1); describe_option("--bias ", "Enable(1) or Disable(0) bias tee (default: 0)", 1); #endif #ifdef WITH_MIRISDR @@ -416,7 +416,7 @@ void usage() { describe_option("--hw-type ", "0 - default, 1 - SDRPlay", 1); describe_option("--gain ", "Set gain (in decibels, from 0 to 102 dB)", 1); describe_option("--correction ", "Set freq correction (in Hertz)", 1); - describe_option("--centerfreq ", "Set center frequency in Hz (default: auto)", 1); + describe_option("--centerfreq ", "Set center frequency (default: auto)", 1); describe_option("--usb-mode ", "0 - isochronous (default), 1 - bulk", 1); #endif #ifdef WITH_SDRPLAY @@ -425,7 +425,7 @@ void usage() { describe_option("--gr ", "Set system gain reduction, in dB, positive (if omitted, auto gain is enabled)", 1); describe_option("--agc ", "Auto gain set point in dBFS, negative (default: -30)", 1); describe_option("--correction ", "Set freq correction (ppm)", 1); - describe_option("--centerfreq ", "Set center frequency in Hz (default: auto)", 1); + describe_option("--centerfreq ", "Set center frequency (default: auto)", 1); describe_option("--antenna ", "RSP2 antenna port selection (default: A)", 1); describe_option("--biast <0/1>", "RSP2/1a/duo Bias-T control: 0 - off (default), 1 - on", 1); describe_option("--notch-filter <0/1>", "RSP2/1a/duo AM/FM/bcast notch filter control: 0 - off (default), 1 - on", 1); @@ -439,7 +439,7 @@ void usage() { describe_option("", "(if omitted, auto gain is enabled)", 1); describe_option("--agc ", "Auto gain set point in dBFS, negative (default: -30)", 1); describe_option("--correction ", "Set freq correction (ppm)", 1); - describe_option("--centerfreq ", "Set center frequency in Hz (default: auto)", 1); + describe_option("--centerfreq ", "Set center frequency (default: auto)", 1); describe_option("--antenna ", "RSP2/dx antenna port selection (default: A)", 1); describe_option("--biast <0/1>", "RSP2/1a/duo/dx Bias-T control: 0 - off (default), 1 - on", 1); describe_option("--notch-filter <0/1>", "RSP2/1a/duo/dx AM/FM/bcast notch filter control: 0 - off (default), 1 - on", 1); @@ -457,7 +457,7 @@ void usage() { #endif fprintf(stderr, "\nfile_options:\n"); describe_option("--iq-file ", "Read I/Q samples from a file (use \"-\" to read from standard input)", 1); - describe_option("--centerfreq ", "Center frequency of the input data, in Hz (default: 0)", 1); + describe_option("--centerfreq ", "Center frequency of the input data, (default: 0)", 1); describe_option("--oversample ", "Oversampling rate for recorded data", 1); fprintf(stderr, "%*s(sampling rate will be set to %u * oversample_rate)\n", USAGE_OPT_NAME_COLWIDTH, "", SYMBOL_RATE * SPS); fprintf(stderr, "%*sDefault: %u\n", USAGE_OPT_NAME_COLWIDTH, "", FILE_OVERSAMPLE); @@ -493,6 +493,11 @@ void usage() { describe_option("--extended-header", "Print additional fields in message header", 1); describe_option("--prettify-xml", "Pretty-print XML payloads in ACARS and MIAM CORE PDUs", 1); describe_option("--prettify-json", "Pretty-print JSON payloads in OHMA messages", 1); + + fprintf(stderr, "\nFrequencies might be specified in Hz (as integer numbers) or in kHz, MHz, GHz (as integer\n"); + fprintf(stderr, "or floating-point numbers followed by any of the following suffixes: k, K, m, M, g, G).\n"); + fprintf(stderr, "Examples: 136975000, 136975k, 136.975M, 0.136975G\n"); + _exit(0); } @@ -620,10 +625,60 @@ static uint32_t parse_msg_filterspec(msg_filterspec_t const *filters, void (*hel return fmask; } +static bool parse_frequency(char const *str, uint32_t *result) { + ASSERT(str != NULL); + ASSERT(result != NULL); + + char *endptr = NULL; + double val = strtod(str, &endptr); + if(endptr == str) { + fprintf(stderr, "Cannot parse '%s' as frequency: not a valid floating-point number\n", str); + return false; + } else if(errno == ERANGE) { + fprintf(stderr, "Cannot parse '%s' as frequency: value too large\n", str); + return false; + } + + switch(endptr[0]) { + case 'k': + case 'K': + val *= 1e3; + endptr++; + break; + case 'm': + case 'M': + val *= 1e6; + endptr++; + break; + case 'g': + case 'G': + val *= 1e9; + endptr++; + break; + case '\0': + break; + default: + fprintf(stderr, "Cannot parse '%s' as frequency: '%c' is not a valid suffix\n", str, endptr[0]); + return false; + } + if(endptr[0] != '\0') { + fprintf(stderr, "Cannot parse '%s' as frequency: invalid trailing characters after value\n", str); + return false; + } + if(val < 0 || val > UINT32_MAX) { + fprintf(stderr, "Cannot parse '%s' as frequency: value is negative or too large\n", str); + return false; + } + *result = (uint32_t)val; + debug_print(D_MISC, "str: %s val: %u\n", str, *result); + return true; +} + + int main(int argc, char **argv) { vdl2_state_t ctx; uint32_t centerfreq = 0, sample_rate = 0, oversample = 0; - uint32_t *freqs; + uint32_t *freqs = NULL; int num_channels = 0; enum input_types input = INPUT_UNDEF; enum sample_formats sample_fmt = SFMT_UNDEF; @@ -832,7 +887,9 @@ int main(int argc, char **argv) { Config.station_id = strndup(optarg, STATION_ID_LEN_MAX); break; case __OPT_CENTERFREQ: - centerfreq = strtoul(optarg, NULL, 10); + if(parse_frequency(optarg, ¢erfreq) == false) { + _exit(1); + } break; #ifdef WITH_MIRISDR case __OPT_MIRISDR: @@ -979,7 +1036,9 @@ int main(int argc, char **argv) { num_channels = argc - optind; freqs = XCALLOC(num_channels, sizeof(uint32_t)); for(int i = 0; i < num_channels; i++) - freqs[i] = strtoul(argv[optind+i], NULL, 10); + if(parse_frequency(argv[optind + i], &freqs[i]) == false) { + return 1; + } } else { fprintf(stderr, "Warning: frequency not set - using VDL2 Common Signalling Channel as a default (%u Hz)\n", CSC_FREQ); num_channels = 1;