From 4c80e60c97bbc055bbb2877ce4a2bfab06e34898 Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" Date: Fri, 23 Nov 2018 08:46:43 +0000 Subject: [PATCH] Allow multiple input files, positional args are input files --- README.md | 2 + src/data.c | 3 ++ src/rtl_433.c | 140 ++++++++++++++++++++++++++++---------------------- 3 files changed, 85 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 33fa795e..76b967eb 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,11 @@ Usage: = General options = [-r ] Read data from input file instead of a receiver [-w ] Save data stream to output file (a '-' dumps samples to stdout) [-W ] Save data stream to output file, overwrite existing file + = Data output options = [-F] kv|json|csv|syslog|null Produce decoded output in given format. Not yet supported by all drivers. Append output to file with : (e.g. -F csv:log.csv), defaults to stdout. Specify host/port for syslog with e.g. -F syslog:127.0.0.1:1514 + [-K] FILE|PATH| Add an expanded token or fixed tag to every output line. [-C] native|si|customary Convert units in decoded output. [-T] Specify number of seconds to run [-U] Print timestamps in UTC (this may also be accomplished by invocation with TZ environment variable set). diff --git a/src/data.c b/src/data.c index c54a6f76..0ff5c2c4 100644 --- a/src/data.c +++ b/src/data.c @@ -302,6 +302,9 @@ data_t *data_prepend(data_t *first, const char *key, const char *pretty_key, ... data_t *result = vdata_make(NULL, key, pretty_key, ap); va_end(ap); + if (!result) + return first; + data_t *prev = result; while (prev && prev->next) prev = prev->next; diff --git a/src/rtl_433.c b/src/rtl_433.c index 41998292..728fb545 100644 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -38,6 +38,7 @@ #define MAX_DATA_OUTPUTS 32 #define MAX_DUMP_OUTPUTS 8 +#define MAX_IN_FILES 100 #ifdef GIT_VERSION #define STR_VALUE(arg) #arg @@ -61,6 +62,8 @@ struct app_cfg { int ppm_error; uint32_t out_block_size; char const *test_data; + unsigned in_files; + char const *in_file[MAX_IN_FILES]; char const *in_filename; int do_exit; int do_exit_async; @@ -175,9 +178,11 @@ static void usage(r_device *devices, unsigned num_devices, int exit_code) "\t[-r ] Read data from input file instead of a receiver\n" "\t[-w ] Save data stream to output file (a '-' dumps samples to stdout)\n" "\t[-W ] Save data stream to output file, overwrite existing file\n" + "\t= Data output options =\n" "\t[-F] kv|json|csv|syslog|null Produce decoded output in given format. Not yet supported by all drivers.\n" "\t\t Append output to file with : (e.g. -F csv:log.csv), defaults to stdout.\n" "\t\t Specify host/port for syslog with e.g. -F syslog:127.0.0.1:1514\n" + "\t[-K] FILE|PATH| Add an expanded token or fixed tag to every output line.\n" "\t[-C] native|si|customary Convert units in decoded output.\n" "\t[-T] Specify number of seconds to run\n" "\t[-U] Print timestamps in UTC (this may also be accomplished by invocation with TZ environment variable set).\n" @@ -940,6 +945,15 @@ static void add_dumper(char const *spec, file_info_t *dumper, int overwrite) } } +static void add_infile(char const *in_file) +{ + if (cfg.in_files >= MAX_IN_FILES) { + fprintf(stderr, "Max input files reached, ignoring \"%s\"!\n", in_file); + return; + } + cfg.in_file[cfg.in_files++] = in_file; +} + /// string to bool with default int atobv(char *arg, int def) { @@ -1146,7 +1160,7 @@ static void parse_conf_option(struct app_cfg *cfg, int opt, char *arg) if (!arg) help_read(); - cfg->in_filename = arg; + add_infile(arg); // TODO: check_read_file_info() break; case 'w': @@ -1350,6 +1364,11 @@ int main(int argc, char **argv) { parse_conf_args(&cfg, argc, argv); + // add all remaining positional arguments as input files + while (argc > optind) { + add_infile(argv[optind++]); + } + if (demod->am_analyze) { demod->am_analyze->level_limit = &demod->level_limit; demod->am_analyze->frequency = &cfg.center_frequency; @@ -1357,12 +1376,6 @@ int main(int argc, char **argv) { demod->am_analyze->sample_size = &demod->sample_size; } - if (argc <= optind - 1) { - usage(NULL, 0, 1); - } else { - out_filename = argv[optind]; // deprecated - } - if (cfg.last_output_handler < 1) { add_kv_output(NULL); } @@ -1409,7 +1422,7 @@ int main(int argc, char **argv) { exit(!r); } - if (!cfg.in_filename) { + if (!cfg.in_files) { r = sdr_open(&cfg.dev, &demod->sample_size, cfg.dev_query, !cfg.quiet_mode); if (r < 0) { exit(1); @@ -1442,8 +1455,7 @@ int main(int argc, char **argv) { add_dumper(out_filename, demod->dumper, 0); // deprecated } - if (cfg.in_filename) { - parse_file_info(cfg.in_filename, &demod->load_info); + if (cfg.in_files) { unsigned char *test_mode_buf = malloc(DEFAULT_BUF_LENGTH * sizeof(unsigned char)); float *test_mode_float_buf = malloc(DEFAULT_BUF_LENGTH / sizeof(int16_t) * sizeof(float)); if (!test_mode_buf || !test_mode_float_buf) @@ -1451,62 +1463,70 @@ int main(int argc, char **argv) { fprintf(stderr, "Couldn't allocate read buffers!\n"); exit(1); } - if (strcmp(demod->load_info.path, "-") == 0) { /* read samples from stdin */ - in_file = stdin; - cfg.in_filename = ""; - } else { - in_file = fopen(demod->load_info.path, "rb"); - if (!in_file) { - fprintf(stderr, "Opening file: %s failed!\n", cfg.in_filename); - goto out; - } - } - fprintf(stderr, "Test mode active. Reading samples from file: %s\n", cfg.in_filename); // Essential information (not quiet) - if (demod->load_info.format == CU8_IQ - || demod->load_info.format == S16_AM - || demod->load_info.format == S16_FM) { - demod->sample_size = sizeof(uint8_t); // CU8, AM, FM - } else { - demod->sample_size = sizeof(int16_t); // CF32, CS16 - } - if (!cfg.quiet_mode) { - fprintf(stderr, "Input format: %s\n", file_info_string(&demod->load_info)); - } - sample_file_pos = 0.0; - int n_blocks = 0; - unsigned long n_read; - do { - if (demod->load_info.format == CF32_IQ) { - n_read = fread(test_mode_float_buf, sizeof(float), DEFAULT_BUF_LENGTH / 2, in_file); - // clamp float to [-1,1] and scale to Q0.15 - for(unsigned long n = 0; n < n_read; n++) { - int s_tmp = test_mode_float_buf[n] * INT16_MAX; - if (s_tmp < -INT16_MAX) - s_tmp = -INT16_MAX; - else if (s_tmp > INT16_MAX) - s_tmp = INT16_MAX; - test_mode_buf[n] = (int16_t)s_tmp; - } + for (i = 0; i < cfg.in_files; ++i) { + cfg.in_filename = cfg.in_file[i]; + + parse_file_info(cfg.in_filename, &demod->load_info); + if (strcmp(demod->load_info.path, "-") == 0) { /* read samples from stdin */ + in_file = stdin; + cfg.in_filename = ""; } else { - n_read = fread(test_mode_buf, 1, DEFAULT_BUF_LENGTH, in_file); + in_file = fopen(demod->load_info.path, "rb"); + if (!in_file) { + fprintf(stderr, "Opening file: %s failed!\n", cfg.in_filename); + goto out; + } } - if (n_read == 0) break; // sdr_callback() will Segmentation Fault with len=0 - sdr_callback(test_mode_buf, n_read, demod); - n_blocks++; - sample_file_pos = (float)n_blocks * n_read / cfg.samp_rate / 2 / demod->sample_size; - } while (n_read != 0); + fprintf(stderr, "Test mode active. Reading samples from file: %s\n", cfg.in_filename); // Essential information (not quiet) + if (demod->load_info.format == CU8_IQ + || demod->load_info.format == S16_AM + || demod->load_info.format == S16_FM) { + demod->sample_size = sizeof(uint8_t); // CU8, AM, FM + } else { + demod->sample_size = sizeof(int16_t); // CF32, CS16 + } + if (!cfg.quiet_mode) { + fprintf(stderr, "Input format: %s\n", file_info_string(&demod->load_info)); + } + sample_file_pos = 0.0; - // Call a last time with cleared samples to ensure EOP detection - memset(test_mode_buf, 128, DEFAULT_BUF_LENGTH); // 128 is 0 in unsigned data - sdr_callback(test_mode_buf, DEFAULT_BUF_LENGTH, demod); + int n_blocks = 0; + unsigned long n_read; + do { + if (demod->load_info.format == CF32_IQ) { + n_read = fread(test_mode_float_buf, sizeof(float), DEFAULT_BUF_LENGTH / 2, in_file); + // clamp float to [-1,1] and scale to Q0.15 + for(unsigned long n = 0; n < n_read; n++) { + int s_tmp = test_mode_float_buf[n] * INT16_MAX; + if (s_tmp < -INT16_MAX) + s_tmp = -INT16_MAX; + else if (s_tmp > INT16_MAX) + s_tmp = INT16_MAX; + test_mode_buf[n] = (int16_t)s_tmp; + } + } else { + n_read = fread(test_mode_buf, 1, DEFAULT_BUF_LENGTH, in_file); + } + if (n_read == 0) break; // sdr_callback() will Segmentation Fault with len=0 + sdr_callback(test_mode_buf, n_read, demod); + n_blocks++; + sample_file_pos = (float)n_blocks * n_read / cfg.samp_rate / 2 / demod->sample_size; + } while (n_read != 0); + + // Call a last time with cleared samples to ensure EOP detection + memset(test_mode_buf, 128, DEFAULT_BUF_LENGTH); // 128 is 0 in unsigned data + sdr_callback(test_mode_buf, DEFAULT_BUF_LENGTH, demod); + + //Always classify a signal at the end of the file + if (demod->am_analyze) + am_analyze_classify(demod->am_analyze); + if (!cfg.quiet_mode) { + fprintf(stderr, "Test mode file issued %d packets\n", n_blocks); + } - //Always classify a signal at the end of the file - if (demod->am_analyze) - am_analyze_classify(demod->am_analyze); - if (!cfg.quiet_mode) { - fprintf(stderr, "Test mode file issued %d packets\n", n_blocks); } + free(test_mode_buf); free(test_mode_float_buf); exit(0);