X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/337eb4ba945097205fbb6a3ca7912fb0697092d1..refs/heads/master:/src/rtl_433.c diff --git a/src/rtl_433.c b/src/rtl_433.c old mode 100644 new mode 100755 index 52d54ab..945b532 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -20,117 +20,59 @@ * along with this program. If not, see . */ +#include + #include "rtl-sdr.h" #include "rtl_433.h" -#include "rtl_433_devices.h" +#include "baseband.h" +#include "pulse_detect.h" +#include "pulse_demod.h" +#include "data.h" +#include "util.h" + static int do_exit = 0; static int do_exit_async = 0, frequencies = 0, events = 0; uint32_t frequency[MAX_PROTOCOLS]; time_t rawtime_old; +int duration = 0; +time_t stop_time; int flag; uint32_t samp_rate = DEFAULT_SAMPLE_RATE; +float sample_file_pos = -1; static uint32_t bytes_to_read = 0; static rtlsdr_dev_t *dev = NULL; -static uint16_t scaled_squares[256]; static int override_short = 0; static int override_long = 0; +int include_only = 0; // Option -I int debug_output = 0; +int quiet_mode = 0; +int utc_mode = 0; +int overwrite_mode = 0; -int debug_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { - int i,j,k; - int rows_used[BITBUF_ROWS]; - int col_max = 0; - int row_cnt = 0; - - // determine what part of bb[][] has non-zero data to avoid - // outputting lots of empty rows - for (i=0 ; i 0 ; j--) { - if (bb[i][j] != 0) - break; - } - if (j != 0) { - rows_used[i] = 1; - row_cnt++; - if (j > col_max) - col_max = j; - } else { - rows_used[i] = 0; - } - } - - if (!row_cnt) { - fprintf(stderr, "debug_callback: empty data array\n"); - return 0; - } - - fprintf(stderr, "\n"); - for (i=0 ; i=0 ; k--) { - if (bb[i][j] & 1<] (default: 0)\n" + "\t[-g ] (default: 0 for auto)\n" + "\t[-f ] [-f...] Receive frequency(s) (default: %i Hz)\n" + "\t[-p ] Set sample rate (default: %i Hz)\n" + "\t[-S] Force sync output (default: async)\n" + "\t= Demodulator options =\n" + "\t[-R ] Enable only the specified device decoding protocol (can be used multiple times)\n" + "\t[-G] Enable all device protocols, included those disabled by default\n" + "\t[-l ] Change detection level used to determine pulses [0-16384] (0 = auto) (default: %i)\n" + "\t[-z ] Override short value in data decoder\n" + "\t[-x ] Override long value in data decoder\n" + "\t[-n ] Specify number of samples to take (each sample is 2 bytes: 1 each of I & Q)\n" + "\t= Analyze/Debug options =\n" + "\t[-a] Analyze mode. Print a textual description of the signal. Disables decoding\n" + "\t[-A] Pulse Analyzer. Enable pulse analyzis and decode attempt\n" + "\t[-I] Include only: 0 = all (default), 1 = unknown devices, 2 = known devices\n" + "\t[-D] Print debug info on event (repeat for more info)\n" + "\t[-q] Quiet mode, suppress non-data messages\n" + "\t[-W] Overwrite mode, disable checks to prevent files from being overwritten\n" + "\t= File I/O options =\n" + "\t[-t] Test signal auto save. Use it together with analyze mode (-a -t). Creates one file per signal\n" + "\t\t Note: Saves raw I/Q samples (uint8 pcm, 2 channel). Preferred mode for generating test files\n" + "\t[-r ] Read data from input file instead of a receiver\n" + "\t[-m ] Data file mode for input / output file (default: 0)\n" + "\t\t 0 = Raw I/Q samples (uint8, 2 channel)\n" + "\t\t 1 = AM demodulated samples (int16 pcm, 1 channel)\n" + "\t\t 2 = FM demodulated samples (int16) (experimental)\n" + "\t\t 3 = Raw I/Q samples (cf32, 2 channel)\n" + "\t\t Note: If output file is specified, input will always be I/Q\n" + "\t[-F] kv|json|csv Produce decoded output in given format. Not yet supported by all drivers.\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" + "\t[] Save data stream to output file (a '-' dumps samples to stdout)\n\n", + DEFAULT_FREQUENCY, DEFAULT_SAMPLE_RATE, DEFAULT_LEVEL_LIMIT); + + fprintf(stderr, "Supported device protocols:\n"); + for (i = 0; i < num_r_devices; i++) { + if (devices[i].disabled) + disabledc = '*'; + else + disabledc = ' '; + + fprintf(stderr, " [%02d]%c %s\n", i + 1, disabledc, devices[i].name); + } + fprintf(stderr, "\n* Disabled by default, use -R n or -G\n"); + exit(1); } @@ -191,108 +171,30 @@ static void sighandler(int signum) { } #endif -/* precalculate lookup table for envelope detection */ -static void calc_squares() { - int i; - for (i = 0; i < 256; i++) - scaled_squares[i] = (128 - i) * (128 - i); -} - -/** This will give a noisy envelope of OOK/ASK signals - * Subtract the bias (-128) and get an envelope estimation - * The output will be written in the input buffer - * @returns pointer to the input buffer - */ - -static void envelope_detect(unsigned char *buf, uint32_t len, int decimate) { - uint16_t* sample_buffer = (uint16_t*) buf; - unsigned int i; - unsigned op = 0; - unsigned int stride = 1 << decimate; - - for (i = 0; i < len / 2; i += stride) { - sample_buffer[op++] = scaled_squares[buf[2 * i ]] + scaled_squares[buf[2 * i + 1]]; - } -} - -static void demod_reset_bits_packet(struct protocol_state* p) { - memset(p->bits_buffer, 0, BITBUF_ROWS * BITBUF_COLS); - memset(p->bits_per_row, 0, BITBUF_ROWS); - p->bits_col_idx = 0; - p->bits_bit_col_idx = 7; - p->bits_row_idx = 0; - p->bit_rows = 0; -} - -static void demod_add_bit(struct protocol_state* p, int bit) { - p->bits_buffer[p->bits_row_idx][p->bits_col_idx] |= bit << p->bits_bit_col_idx; - p->bits_bit_col_idx--; - if (p->bits_bit_col_idx < 0) { - p->bits_bit_col_idx = 7; - p->bits_col_idx++; - if (p->bits_col_idx > BITBUF_COLS - 1) { - p->bits_col_idx = BITBUF_COLS - 1; - // fprintf(stderr, "p->bits_col_idx>%i!\n", BITBUF_COLS-1); - } - } - p->bits_per_row[p->bit_rows]++; -} - -static void demod_next_bits_packet(struct protocol_state* p) { - p->bits_col_idx = 0; - p->bits_row_idx++; - p->bits_bit_col_idx = 7; - if (p->bits_row_idx > BITBUF_ROWS - 1) { - p->bits_row_idx = BITBUF_ROWS - 1; - //fprintf(stderr, "p->bits_row_idx>%i!\n", BITBUF_ROWS-1); - } - p->bit_rows++; - if (p->bit_rows > BITBUF_ROWS - 1) - p->bit_rows -= 1; -} - -static void demod_print_bits_packet(struct protocol_state* p) { - int i, j, k; - - fprintf(stderr, "\n"); - for (i = 0; i < p->bit_rows + 1; i++) { - fprintf(stderr, "[%02d] {%d} ", i, p->bits_per_row[i]); - for (j = 0; j < ((p->bits_per_row[i] + 8) / 8); j++) { - fprintf(stderr, "%02x ", p->bits_buffer[i][j]); - } - fprintf(stderr, ": "); - for (j = 0; j < ((p->bits_per_row[i] + 8) / 8); j++) { - for (k = 7; k >= 0; k--) { - if (p->bits_buffer[i][j] & 1 << k) - fprintf(stderr, "1"); - else - fprintf(stderr, "0"); - } - // fprintf(stderr, "=0x%x ",demod->bits_buffer[i][j]); - fprintf(stderr, " "); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); - return; -} static void register_protocol(struct dm_state *demod, r_device *t_dev) { struct protocol_state *p = calloc(1, sizeof (struct protocol_state)); - p->short_limit = (float) t_dev->short_limit / ((float) DEFAULT_SAMPLE_RATE / (float) samp_rate); - p->long_limit = (float) t_dev->long_limit / ((float) DEFAULT_SAMPLE_RATE / (float) samp_rate); - p->reset_limit = (float) t_dev->reset_limit / ((float) DEFAULT_SAMPLE_RATE / (float) samp_rate); + p->short_limit = (float) t_dev->short_limit / ((float) 1000000 / (float) samp_rate); + p->long_limit = (float) t_dev->long_limit / ((float) 1000000 / (float) samp_rate); + p->reset_limit = (float) t_dev->reset_limit / ((float) 1000000 / (float) samp_rate); p->modulation = t_dev->modulation; p->callback = t_dev->json_callback; - demod_reset_bits_packet(p); + p->name = t_dev->name; + p->demod_arg = t_dev->demod_arg; + bitbuffer_clear(&p->bits); demod->r_devs[demod->r_dev_num] = p; demod->r_dev_num++; - fprintf(stderr, "Registering protocol[%02d] %s\n", demod->r_dev_num, t_dev->name); + if (!quiet_mode) { + fprintf(stderr, "Registering protocol [%d] \"%s\"\n", demod->r_dev_num, t_dev->name); + } - if (demod->r_dev_num > MAX_PROTOCOLS) - fprintf(stderr, "Max number of protocols reached %d\n", MAX_PROTOCOLS); + if (demod->r_dev_num > MAX_PROTOCOLS) { + fprintf(stderr, "\n\nMax number of protocols reached %d\n", MAX_PROTOCOLS); + fprintf(stderr, "Increase MAX_PROTOCOLS and recompile\n"); + exit(-1); + } } @@ -310,6 +212,56 @@ static unsigned int signal_pulse_data[4000][3] = { {0}}; static unsigned int signal_pulse_counter = 0; +typedef struct output_handler { + /*data_printer_t*/ void *printer; + void (*aux_free)(void *aux); + FILE *file; + void *aux; + struct output_handler *next; +} output_handler_t; +static output_handler_t *output_handler = NULL; +static output_handler_t **next_output_handler = &output_handler; + +/* handles incoming structured data by dumping it */ +void data_acquired_handler(data_t *data) +{ + if (conversion_mode == CONVERT_SI) { + for (data_t *d = data; d; d = d->next) { + if ((d->type == DATA_DOUBLE) && + !strcmp(d->key, "temperature_F")) { + *(double*)d->value = fahrenheit2celsius(*(double*)d->value); + free(d->key); + d->key = strdup("temperature_C"); + char *pos; + if (d->format && + (pos = strrchr(d->format, 'F'))) { + *pos = 'C'; + } + } + } + } + if (conversion_mode == CONVERT_CUSTOMARY) { + for (data_t *d = data; d; d = d->next) { + if ((d->type == DATA_DOUBLE) && + !strcmp(d->key, "temperature_C")) { + *(double*)d->value = celsius2fahrenheit(*(double*)d->value); + free(d->key); + d->key = strdup("temperature_F"); + char *pos; + if (d->format && + (pos = strrchr(d->format, 'C'))) { + *pos = 'F'; + } + } + } + } + + for (output_handler_t *output = output_handler; output; output = output->next) { + data_print(data, output->file, output->printer, output->aux); + } + data_free(data); +} + static void classify_signal() { unsigned int i, k, max = 0, min = 1000000, t; unsigned int delta, count_min, count_max, min_new, max_new, p_limit; @@ -477,56 +429,48 @@ static void classify_signal() { a[1] = override_long; } - if (a[1] 0) { if (signal_distance_data[i] < (a[0] + a[1]) / 2) { // fprintf(stderr, "0 [%d] %d < %d\n",i, signal_distance_data[i], (a[0]+a[1])/2); - demod_add_bit(&p, 0); + bitbuffer_add_bit(&p.bits, 0); } else if ((signal_distance_data[i] > (a[0] + a[1]) / 2) && (signal_distance_data[i] < (a[1] + a[2]) / 2)) { // fprintf(stderr, "0 [%d] %d > %d\n",i, signal_distance_data[i], (a[0]+a[1])/2); - demod_add_bit(&p, 1); + bitbuffer_add_bit(&p.bits, 1); } else if (signal_distance_data[i] > (a[1] + a[2]) / 2) { // fprintf(stderr, "0 [%d] %d > %d\n",i, signal_distance_data[i], (a[1]+a[2])/2); - demod_next_bits_packet(&p); + bitbuffer_add_row(&p.bits); } } } - demod_print_bits_packet(&p); + bitbuffer_print(&p.bits); } if (signal_type == 2) { for (i = 0; i < 1000; i++) { if (signal_pulse_data[i][2] > 0) { if (signal_pulse_data[i][2] < p_limit) { // fprintf(stderr, "0 [%d] %d < %d\n",i, signal_pulse_data[i][2], p_limit); - demod_add_bit(&p, 0); + bitbuffer_add_bit(&p.bits, 0); } else { // fprintf(stderr, "1 [%d] %d > %d\n",i, signal_pulse_data[i][2], p_limit); - demod_add_bit(&p, 1); + bitbuffer_add_bit(&p.bits, 1); } if ((signal_distance_data[i] >= (a[1] + a[2]) / 2)) { // fprintf(stderr, "\\n [%d] %d > %d\n",i, signal_distance_data[i], (a[1]+a[2])/2); - demod_next_bits_packet(&p); + bitbuffer_add_row(&p.bits); } } } - demod_print_bits_packet(&p); + bitbuffer_print(&p.bits); } for (i = 0; i < 1000; i++) { @@ -540,9 +484,10 @@ static void classify_signal() { static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) { unsigned int i; + int32_t threshold = (demod->level_limit ? demod->level_limit : 8000); // Does not support auto level. Use old default instead. for (i = 0; i < len; i++) { - if (buf[i] > demod->level_limit) { + if (buf[i] > threshold) { if (!signal_start) signal_start = counter; if (print) { @@ -560,7 +505,7 @@ static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) { } } counter++; - if (buf[i] < demod->level_limit) { + if (buf[i] < threshold) { if (print2) { pulse_avg += counter - pulse_start; if (debug_output) fprintf(stderr, "pulse_end [%d] found at sample %d, pulse length = %d, pulse avg length = %d\n", @@ -589,8 +534,14 @@ static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) { char sgf_name[256] = {0}; FILE *sgfp; - sprintf(sgf_name, "gfile%03d.data", demod->signal_grabber); - demod->signal_grabber++; + while (1) { + sprintf(sgf_name, "gfile%03d.data", demod->signal_grabber); + demod->signal_grabber++; + if (access(sgf_name, F_OK) == -1 || overwrite_mode) { + break; + } + } + signal_bszie = 2 * (signal_end - (signal_start - 10000)); signal_bszie = (131072 - (signal_bszie % 131072)) + signal_bszie; sg_idx = demod->sg_index - demod->sg_len; @@ -641,310 +592,285 @@ err: return; } -/* The distance between pulses decodes into bits */ - -static void pwm_d_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) { - unsigned int i; - - for (i = 0; i < len; i++) { - if (buf[i] > demod->level_limit) { - p->pulse_count = 1; - p->start_c = 1; - } - if (p->pulse_count && (buf[i] < demod->level_limit)) { - p->pulse_length = 0; - p->pulse_distance = 1; - p->sample_counter = 0; - p->pulse_count = 0; - } - if (p->start_c) p->sample_counter++; - if (p->pulse_distance && (buf[i] > demod->level_limit)) { - if (p->sample_counter < p->short_limit) { - demod_add_bit(p, 0); - } else if (p->sample_counter < p->long_limit) { - demod_add_bit(p, 1); - } else { - demod_next_bits_packet(p); - p->pulse_count = 0; - p->sample_counter = 0; - } - p->pulse_distance = 0; - } - if (p->sample_counter > p->reset_limit) { - p->start_c = 0; - p->sample_counter = 0; - p->pulse_distance = 0; - if (p->callback) - events += p->callback(p->bits_buffer, p->bits_per_row); - else - demod_print_bits_packet(p); - demod_reset_bits_packet(p); - } - } -} - -/* The length of pulses decodes into bits */ +static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) { + struct dm_state *demod = ctx; + int i; + char time_str[LOCAL_TIME_BUFLEN]; -static void pwm_p_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) { - unsigned int i; + if (do_exit || do_exit_async) + return; - for (i = 0; i < len; i++) { - if (buf[i] > demod->level_limit && !p->start_bit) { - /* start bit detected */ - p->start_bit = 1; - p->start_c = 1; - p->sample_counter = 0; - // fprintf(stderr, "start bit pulse start detected\n"); - } + if ((bytes_to_read > 0) && (bytes_to_read < len)) { + len = bytes_to_read; + do_exit = 1; + rtlsdr_cancel_async(dev); + } - if (!p->real_bits && p->start_bit && (buf[i] < demod->level_limit)) { - /* end of startbit */ - p->real_bits = 1; - p->pulse_length = 0; - p->sample_counter = 0; - // fprintf(stderr, "start bit pulse end detected\n"); - } - if (p->start_c) p->sample_counter++; + if (demod->signal_grabber) { + //fprintf(stderr, "[%d] sg_index - len %d\n", demod->sg_index, len ); + memcpy(&demod->sg_buf[demod->sg_index], iq_buf, len); + demod->sg_len = len; + demod->sg_index += len; + if (demod->sg_index + len > SIGNAL_GRABBER_BUFFER) + demod->sg_index = 0; + } + // AM demodulation + envelope_detect(iq_buf, demod->temp_buf, len/2); + baseband_low_pass_filter(demod->temp_buf, demod->am_buf, len/2, &demod->lowpass_filter_state); - if (!p->pulse_start && p->real_bits && (buf[i] > demod->level_limit)) { - /* save the pulse start, it will never be zero */ - p->pulse_start = p->sample_counter; - // fprintf(stderr, "real bit pulse start detected\n"); + // FM demodulation + if (demod->enable_FM_demod) { + baseband_demod_FM(iq_buf, demod->fm_buf, len/2, &demod->demod_FM_state); + } - } + // Handle special input formats + if(!demod->out_file) { // If output file is specified we always assume I/Q input + if (demod->debug_mode == 1) { // The IQ buffer is really AM demodulated data + memcpy(demod->am_buf, iq_buf, len); + } else if (demod->debug_mode == 2) { // The IQ buffer is really FM demodulated data + fprintf(stderr, "Reading FM modulated data not implemented yet!\n"); + } + } - if (p->real_bits && p->pulse_start && (buf[i] < demod->level_limit)) { - /* end of pulse */ + if (demod->analyze || (demod->out_file == stdout)) { // We don't want to decode devices when outputting to stdout + pwm_analyze(demod, demod->am_buf, len / 2); + } else { + // Detect a package and loop through demodulators with pulse data + int package_type = 1; // Just to get us started + while(package_type) { + int p_events = 0; // Sensor events successfully detected per package + package_type = pulse_detect_package(demod->am_buf, demod->fm_buf, len/2, demod->level_limit, samp_rate, &demod->pulse_data, &demod->fsk_pulse_data); + if (package_type == 1) { + if(demod->analyze_pulses) fprintf(stderr, "Detected OOK package\t@ %s\n", local_time_str(0, time_str)); + for (i = 0; i < demod->r_dev_num; i++) { + switch (demod->r_devs[i]->modulation) { + case OOK_PULSE_PCM_RZ: + p_events += pulse_demod_pcm(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_PPM_RAW: + p_events += pulse_demod_ppm(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_PWM_PRECISE: + p_events += pulse_demod_pwm_precise(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_PWM_RAW: + p_events += pulse_demod_pwm(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_PWM_TERNARY: + p_events += pulse_demod_pwm_ternary(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_MANCHESTER_ZEROBIT: + p_events += pulse_demod_manchester_zerobit(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_CLOCK_BITS: + p_events += pulse_demod_clock_bits(&demod->pulse_data, demod->r_devs[i]); + break; + case OOK_PULSE_PWM_OSV1: + p_events += pulse_demod_osv1(&demod->pulse_data, demod->r_devs[i]); + break; + // FSK decoders + case FSK_PULSE_PCM: + case FSK_PULSE_PWM_RAW: + break; + case FSK_PULSE_MANCHESTER_ZEROBIT: + p_events += pulse_demod_manchester_zerobit(&demod->pulse_data, demod->r_devs[i]); + break; + default: + fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation); + } + } // for demodulators + if(debug_output > 1) pulse_data_print(&demod->pulse_data); + if(demod->analyze_pulses && (include_only == 0 || (include_only == 1 && p_events == 0) || (include_only == 2 && p_events > 0)) ) { + pulse_analyzer(&demod->pulse_data, samp_rate); + } + } else if (package_type == 2) { + if(demod->analyze_pulses) fprintf(stderr, "Detected FSK package\t@ %s\n", local_time_str(0, time_str)); + for (i = 0; i < demod->r_dev_num; i++) { + switch (demod->r_devs[i]->modulation) { + // OOK decoders + case OOK_PULSE_PCM_RZ: + case OOK_PULSE_PPM_RAW: + case OOK_PULSE_PWM_PRECISE: + case OOK_PULSE_PWM_RAW: + case OOK_PULSE_PWM_TERNARY: + case OOK_PULSE_MANCHESTER_ZEROBIT: + case OOK_PULSE_CLOCK_BITS: + case OOK_PULSE_PWM_OSV1: + break; + case FSK_PULSE_PCM: + p_events += pulse_demod_pcm(&demod->fsk_pulse_data, demod->r_devs[i]); + break; + case FSK_PULSE_PWM_RAW: + p_events += pulse_demod_pwm(&demod->fsk_pulse_data, demod->r_devs[i]); + break; + case FSK_PULSE_MANCHESTER_ZEROBIT: + p_events += pulse_demod_manchester_zerobit(&demod->fsk_pulse_data, demod->r_devs[i]); + break; + default: + fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation); + } + } // for demodulators + if(debug_output > 1) pulse_data_print(&demod->fsk_pulse_data); + if(demod->analyze_pulses && (include_only == 0 || (include_only == 1 && p_events == 0) || (include_only == 2 && p_events > 0)) ) { + pulse_analyzer(&demod->fsk_pulse_data, samp_rate); + } + } // if (package_type == ... + } // while(package_type)... + } // if (demod->analyze... + + if (demod->out_file) { + uint8_t* out_buf = iq_buf; // Default is to dump IQ samples + if (demod->debug_mode == 1) { // AM data + out_buf = (uint8_t*)demod->am_buf; + } else if (demod->debug_mode == 2) { // FM data + out_buf = (uint8_t*)demod->fm_buf; + } + if (fwrite(out_buf, 1, len, demod->out_file) != len) { + fprintf(stderr, "Short write, samples lost, exiting!\n"); + rtlsdr_cancel_async(dev); + } + } - p->pulse_length = p->sample_counter - p->pulse_start; - // fprintf(stderr, "real bit pulse end detected %d\n", p->pulse_length); - // fprintf(stderr, "space duration %d\n", p->sample_counter); + if (bytes_to_read > 0) + bytes_to_read -= len; + + time_t rawtime; + time(&rawtime); + if (frequencies > 1) { + if (difftime(rawtime, rawtime_old) > DEFAULT_HOP_TIME || events >= DEFAULT_HOP_EVENTS) { + rawtime_old = rawtime; + events = 0; + do_exit_async = 1; + rtlsdr_cancel_async(dev); + } + } + if (duration > 0 && rawtime >= stop_time) { + do_exit_async = do_exit = 1; + fprintf(stderr, "Time expired, exiting!\n"); + rtlsdr_cancel_async(dev); + } +} - if (p->pulse_length <= p->short_limit) { - demod_add_bit(p, 1); - } else if (p->pulse_length > p->short_limit) { - demod_add_bit(p, 0); +// find the fields output for CSV +void *determine_csv_fields(r_device* devices, int num_devices) +{ + int i, j; + int cur_output_fields = 0; + int num_output_fields = 0; + void *csv_aux; + const char **output_fields = NULL; + for (i = 0; i < num_devices; i++) + if (!devices[i].disabled) { + if (devices[i].fields) + for (int c = 0; devices[i].fields[c]; ++c) + ++num_output_fields; + else + fprintf(stderr, "rtl_433: warning: %d \"%s\" does not support CSV output\n", + i, devices[i].name); + } + output_fields = calloc(num_output_fields + 1, sizeof(char*)); + for (i = 0; i < num_devices; i++) { + if (!devices[i].disabled && devices[i].fields) { + for (int c = 0; devices[i].fields[c]; ++c) { + output_fields[cur_output_fields] = devices[i].fields[c]; + ++cur_output_fields; } - p->sample_counter = 0; - p->pulse_start = 0; - } - - if (p->real_bits && (p->pulse_length > p->long_limit)) { - demod_next_bits_packet(p); - - p->start_bit = 0; - p->real_bits = 0; - } - - if (p->sample_counter > p->reset_limit) { - p->start_c = 0; - p->sample_counter = 0; - //demod_print_bits_packet(p); - if (p->callback) - events += p->callback(p->bits_buffer, p->bits_per_row); - else - demod_print_bits_packet(p); - demod_reset_bits_packet(p); - - p->start_bit = 0; - p->real_bits = 0; } } -} -/* Machester Decode for Oregon Scientific Weather Sensors - Decode data streams sent by Oregon Scientific v2.1, and v3 weather sensors. - With manchester encoding, both the pulse width and pulse distance vary. Clock sync - is recovered from the data stream based on pulse widths and distances exceeding a - minimum threashold (short limit* 1.5). - */ -static void manchester_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) { - unsigned int i; - - if (p->sample_counter == 0) - p->sample_counter = p->short_limit*2; - - for (i=0 ; istart_c) - p->sample_counter++; /* For this decode type, sample counter is count since last data bit recorded */ - - if (!p->pulse_count && (buf[i] > demod->level_limit)) { /* Pulse start (rising edge) */ - p->pulse_count = 1; - if (p->sample_counter > (p->short_limit + (p->short_limit>>1))) { - /* Last bit was recorded more than short_limit*1.5 samples ago */ - /* so this pulse start must be a data edge (rising data edge means bit = 0) */ - demod_add_bit(p, 0); - p->sample_counter=1; - p->start_c++; // start_c counts number of bits received - } - } - if (p->pulse_count && (buf[i] <= demod->level_limit)) { /* Pulse end (falling edge) */ - if (p->sample_counter > (p->short_limit + (p->short_limit>>1))) { - /* Last bit was recorded more than "short_limit*1.5" samples ago */ - /* so this pulse end is a data edge (falling data edge means bit = 1) */ - demod_add_bit(p, 1); - p->sample_counter=1; - p->start_c++; - } - p->pulse_count = 0; - } + csv_aux = data_csv_init(output_fields, num_output_fields); + free(output_fields); + return csv_aux; +} - if (p->sample_counter > p->reset_limit) { - //fprintf(stderr, "manchester_decode number of bits received=%d\n",p->start_c); - if (p->callback) - events+=p->callback(p->bits_buffer, p->bits_per_row); - else - demod_print_bits_packet(p); - demod_reset_bits_packet(p); - p->sample_counter = p->short_limit*2; - p->start_c = 0; - } +void add_json_output() +{ + output_handler_t *output = calloc(1, sizeof(output_handler_t)); + if (!output) { + fprintf(stderr, "rtl_433: failed to allocate memory for output handler\n"); + exit(1); } + output->printer = &data_json_printer; + output->file = stdout; + *next_output_handler = output; + next_output_handler = &output->next; } -/** Something that might look like a IIR lowpass filter - * - * [b,a] = butter(1, 0.01) -> quantizes nicely thus suitable for fixed point - * Q1.15*Q15.0 = Q16.15 - * Q16.15>>1 = Q15.14 - * Q15.14 + Q15.14 + Q15.14 could possibly overflow to 17.14 - * but the b coeffs are small so it wont happen - * Q15.14>>14 = Q15.0 \o/ - */ - -static uint16_t lp_xmem[FILTER_ORDER] = {0}; - -#define F_SCALE 15 -#define S_CONST (1<> 1) + (b[0] * x_buf[0] >> 1) + (b[1] * lp_xmem[0] >> 1)) >> (F_SCALE - 1); - for (i = 1; i < len; i++) { - y_buf[i] = ((a[1] * y_buf[i - 1] >> 1) + (b[0] * x_buf[i] >> 1) + (b[1] * x_buf[i - 1] >> 1)) >> (F_SCALE - 1); +void add_csv_output(void *aux_data) +{ + if (!aux_data) { + fprintf(stderr, "rtl_433: failed to allocate memory for CSV auxiliary data\n"); + exit(1); } - - /* Save last sample */ - memcpy(lp_xmem, &x_buf[len - 1 - FILTER_ORDER], FILTER_ORDER * sizeof (int16_t)); - memcpy(&y_buf[-FILTER_ORDER], &y_buf[len - 1 - FILTER_ORDER], FILTER_ORDER * sizeof (int16_t)); - //fprintf(stderr, "%d\n", y_buf[0]); + output_handler_t *output = calloc(1, sizeof(output_handler_t)); + if (!output) { + fprintf(stderr, "rtl_433: failed to allocate memory for output handler\n"); + exit(1); + } + output->printer = &data_csv_printer; + output->aux_free = &data_csv_free; + output->file = stdout; + output->aux = aux_data; + *next_output_handler = output; + next_output_handler = &output->next; } -static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) { - struct dm_state *demod = ctx; - uint16_t* sbuf = (uint16_t*) buf; - int i; - if (demod->file || !demod->save_data) { - if (do_exit || do_exit_async) - return; - - if ((bytes_to_read > 0) && (bytes_to_read < len)) { - len = bytes_to_read; - do_exit = 1; - rtlsdr_cancel_async(dev); - } - - if (demod->signal_grabber) { - //fprintf(stderr, "[%d] sg_index - len %d\n", demod->sg_index, len ); - memcpy(&demod->sg_buf[demod->sg_index], buf, len); - demod->sg_len = len; - demod->sg_index += len; - if (demod->sg_index + len > SIGNAL_GRABBER_BUFFER) - demod->sg_index = 0; - } - - - if (demod->debug_mode == 0) { - envelope_detect(buf, len, demod->decimation_level); - low_pass_filter(sbuf, demod->f_buf, len >> (demod->decimation_level + 1)); - } else if (demod->debug_mode == 1) { - memcpy(demod->f_buf, buf, len); - } - if (demod->analyze) { - pwm_analyze(demod, demod->f_buf, len / 2); - } else { - for (i = 0; i < demod->r_dev_num; i++) { - switch (demod->r_devs[i]->modulation) { - case OOK_PWM_D: - pwm_d_decode(demod, demod->r_devs[i], demod->f_buf, len / 2); - break; - case OOK_PWM_P: - pwm_p_decode(demod, demod->r_devs[i], demod->f_buf, len / 2); - break; - case OOK_MANCHESTER: - manchester_decode(demod, demod->r_devs[i], demod->f_buf, len/2); - break; - default: - fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation); - } - } - fflush(stdout); - } - - if (demod->save_data) { - if (fwrite(demod->f_buf, 1, len >> demod->decimation_level, demod->file) != len >> demod->decimation_level) { - fprintf(stderr, "Short write, samples lost, exiting!\n"); - rtlsdr_cancel_async(dev); - } - } - - if (bytes_to_read > 0) - bytes_to_read -= len; - - if (frequencies > 1) { - time_t rawtime; - time(&rawtime); - if (difftime(rawtime, rawtime_old) > DEFAULT_HOP_TIME || events >= DEFAULT_HOP_EVENTS) { - rawtime_old = rawtime; - events = 0; - do_exit_async = 1; - rtlsdr_cancel_async(dev); - } - } +void add_kv_output() +{ + output_handler_t *output = calloc(1, sizeof(output_handler_t)); + if (!output) { + fprintf(stderr, "rtl_433: failed to allocate memory for output handler\n"); + exit(1); } + output->printer = &data_kv_printer; + output->file = stdout; + *next_output_handler = output; + next_output_handler = &output->next; } int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; #endif - char *filename = NULL; - char *test_mode_file = NULL; - FILE *test_mode; + char *out_filename = NULL; + char *in_filename = NULL; + FILE *in_file; int n_read; - int r, opt; + int r = 0, opt; int i, gain = 0; int sync_mode = 0; int ppm_error = 0; struct dm_state* demod; - uint8_t *buffer; uint32_t dev_index = 0; int frequency_current = 0; uint32_t out_block_size = DEFAULT_BUF_LENGTH; int device_count; char vendor[256], product[256], serial[256]; + int have_opt_R = 0; + int register_all = 0; + + setbuf(stdout, NULL); + setbuf(stderr, NULL); demod = malloc(sizeof (struct dm_state)); memset(demod, 0, sizeof (struct dm_state)); /* initialize tables */ - calc_squares(); + baseband_init(); - demod->f_buf = &demod->filter_buffer[FILTER_ORDER]; - demod->decimation_level = DEFAULT_DECIMATION_LEVEL; - demod->level_limit = DEFAULT_LEVEL_LIMIT; + r_device devices[] = { +#define DECL(name) name, + DEVICES +#undef DECL + }; + num_r_devices = sizeof(devices)/sizeof(*devices); + + demod->level_limit = DEFAULT_LEVEL_LIMIT; - while ((opt = getopt(argc, argv, "x:z:p:Dtam:r:c:l:d:f:g:s:b:n:S::")) != -1) { + while ((opt = getopt(argc, argv, "x:z:p:DtaAI:qm:r:l:d:f:g:s:b:n:SR:F:C:T:UWG")) != -1) { switch (opt) { case 'd': dev_index = atoi(optarg); @@ -956,6 +882,9 @@ int main(int argc, char **argv) { case 'g': gain = (int) (atof(optarg) * 10); /* tenths of a dB */ break; + case 'G': + register_all = 1; + break; case 'p': ppm_error = atoi(optarg); break; @@ -971,14 +900,17 @@ int main(int argc, char **argv) { case 'n': bytes_to_read = (uint32_t) atof(optarg) * 2; break; - case 'c': - demod->decimation_level = (uint32_t) atof(optarg); - break; case 'a': demod->analyze = 1; break; + case 'A': + demod->analyze_pulses = 1; + break; + case 'I': + include_only = atoi(optarg); + break; case 'r': - test_mode_file = optarg; + in_filename = optarg; break; case 't': demod->signal_grabber = 1; @@ -990,7 +922,7 @@ int main(int argc, char **argv) { sync_mode = 1; break; case 'D': - debug_output = 1; + debug_output++; break; case 'z': override_short = atoi(optarg); @@ -998,40 +930,96 @@ int main(int argc, char **argv) { case 'x': override_long = atoi(optarg); break; + case 'R': + if (!have_opt_R) { + for (i = 0; i < num_r_devices; i++) { + devices[i].disabled = 1; + } + have_opt_R = 1; + } + + i = atoi(optarg); + if (i > num_r_devices) { + fprintf(stderr, "Remote device number specified larger than number of devices\n\n"); + usage(devices); + } + + devices[i - 1].disabled = 0; + break; + case 'q': + quiet_mode = 1; + break; + case 'F': + if (strcmp(optarg, "json") == 0) { + add_json_output(); + } else if (strcmp(optarg, "csv") == 0) { + add_csv_output(determine_csv_fields(devices, num_r_devices)); + } else if (strcmp(optarg, "kv") == 0) { + add_kv_output(); + } else { + fprintf(stderr, "Invalid output format %s\n", optarg); + usage(devices); + } + break; + case 'C': + if (strcmp(optarg, "native") == 0) { + conversion_mode = CONVERT_NATIVE; + } else if (strcmp(optarg, "si") == 0) { + conversion_mode = CONVERT_SI; + } else if (strcmp(optarg, "customary") == 0) { + conversion_mode = CONVERT_CUSTOMARY; + } else { + fprintf(stderr, "Invalid conversion mode %s\n", optarg); + usage(devices); + } + break; + case 'U': + #if !defined(__MINGW32__) + utc_mode = setenv("TZ", "UTC", 1); + if(utc_mode != 0) fprintf(stderr, "Unable to set TZ to UTC; error code: %d\n", utc_mode); + #endif + break; + case 'W': + overwrite_mode = 1; + break; + case 'T': + time(&stop_time); + duration = atoi(optarg); + if (duration < 1) { + fprintf(stderr, "Duration '%s' was not positive integer; will continue indefinitely\n", optarg); + } else { + stop_time += duration; + } + break; default: - usage(); + usage(devices); break; } } - /* init protocols somewhat ok */ - register_protocol(demod, &rubicson); - register_protocol(demod, &prologue); - register_protocol(demod, &silvercrest); - // register_protocol(demod, &generic_hx2262); - // register_protocol(demod, &technoline_ws9118); - register_protocol(demod, &elv_em1000); - register_protocol(demod, &elv_ws2000); - register_protocol(demod, &waveman); - register_protocol(demod, &steffen); - register_protocol(demod, &acurite5n1); - register_protocol(demod, &acurite_th); - register_protocol(demod, &acurite_rain_gauge); - register_protocol(demod, &lacrossetx); - register_protocol(demod, &oregon_scientific); - register_protocol(demod, &newkaku); - register_protocol(demod, &alectov1); - register_protocol(demod, &intertechno); - register_protocol(demod, &mebus433); - register_protocol(demod, &wh2); - register_protocol(demod, &leak); - if (argc <= optind - 1) { - usage(); + usage(devices); } else { - filename = argv[optind]; + out_filename = argv[optind]; + } + + if (!output_handler) { + add_kv_output(); } + for (i = 0; i < num_r_devices; i++) { + if (!devices[i].disabled || register_all) { + register_protocol(demod, &devices[i]); + if(devices[i].modulation >= FSK_DEMOD_MIN_VAL) { + demod->enable_FM_demod = 1; + } + } + } + + if (!quiet_mode) + fprintf(stderr,"Registered %d out of %d device decoding protocols\n", + demod->r_dev_num, num_r_devices); + if (out_block_size < MINIMAL_BUF_LENGTH || out_block_size > MAXIMAL_BUF_LENGTH) { fprintf(stderr, @@ -1043,113 +1031,148 @@ int main(int argc, char **argv) { out_block_size = DEFAULT_BUF_LENGTH; } - buffer = malloc(out_block_size * sizeof (uint8_t)); - - device_count = rtlsdr_get_device_count(); - if (!device_count) { - fprintf(stderr, "No supported devices found.\n"); - if (!test_mode_file) - exit(1); - } + if (!in_filename) { + device_count = rtlsdr_get_device_count(); + if (!device_count) { + fprintf(stderr, "No supported devices found.\n"); + if (!in_filename) + exit(1); + } - fprintf(stderr, "Found %d device(s):\n", device_count); - for (i = 0; i < device_count; i++) { - rtlsdr_get_device_usb_strings(i, vendor, product, serial); - fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); - } - fprintf(stderr, "\n"); + if (!quiet_mode) { + fprintf(stderr, "Found %d device(s):\n", device_count); + for (i = 0; i < device_count; i++) { + rtlsdr_get_device_usb_strings(i, vendor, product, serial); + fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); + } + fprintf(stderr, "\n"); - fprintf(stderr, "Using device %d: %s\n", - dev_index, rtlsdr_get_device_name(dev_index)); + fprintf(stderr, "Using device %d: %s\n", + dev_index, rtlsdr_get_device_name(dev_index)); + } - r = rtlsdr_open(&dev, dev_index); - if (r < 0) { - fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); - if (!test_mode_file) - exit(1); - } + r = rtlsdr_open(&dev, dev_index); + if (r < 0) { + fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); + exit(1); + } #ifndef _WIN32 - sigact.sa_handler = sighandler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGQUIT, &sigact, NULL); - sigaction(SIGPIPE, &sigact, NULL); + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGPIPE, &sigact, NULL); #else - SetConsoleCtrlHandler((PHANDLER_ROUTINE) sighandler, TRUE); + SetConsoleCtrlHandler((PHANDLER_ROUTINE) sighandler, TRUE); #endif - /* Set the sample rate */ - r = rtlsdr_set_sample_rate(dev, samp_rate); - if (r < 0) - fprintf(stderr, "WARNING: Failed to set sample rate.\n"); - else - fprintf(stderr, "Sample rate set to %d.\n", rtlsdr_get_sample_rate(dev)); // Unfortunately, doesn't return real rate - - fprintf(stderr, "Sample rate decimation set to %d. %d->%d\n", demod->decimation_level, samp_rate, samp_rate >> demod->decimation_level); - fprintf(stderr, "Bit detection level set to %d.\n", demod->level_limit); - - if (0 == gain) { - /* Enable automatic gain */ - r = rtlsdr_set_tuner_gain_mode(dev, 0); - if (r < 0) - fprintf(stderr, "WARNING: Failed to enable automatic gain.\n"); - else - fprintf(stderr, "Tuner gain set to Auto.\n"); - } else { - /* Enable manual gain */ - r = rtlsdr_set_tuner_gain_mode(dev, 1); - if (r < 0) - fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); - - /* Set the tuner gain */ - r = rtlsdr_set_tuner_gain(dev, gain); - if (r < 0) - fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); - else - fprintf(stderr, "Tuner gain set to %f dB.\n", gain / 10.0); - } + /* Set the sample rate */ + r = rtlsdr_set_sample_rate(dev, samp_rate); + if (r < 0) + fprintf(stderr, "WARNING: Failed to set sample rate.\n"); + else + fprintf(stderr, "Sample rate set to %d.\n", rtlsdr_get_sample_rate(dev)); // Unfortunately, doesn't return real rate + + fprintf(stderr, "Bit detection level set to %d%s.\n", demod->level_limit, (demod->level_limit ? "" : " (Auto)")); + + if (0 == gain) { + /* Enable automatic gain */ + r = rtlsdr_set_tuner_gain_mode(dev, 0); + if (r < 0) + fprintf(stderr, "WARNING: Failed to enable automatic gain.\n"); + else + fprintf(stderr, "Tuner gain set to Auto.\n"); + } else { + /* Enable manual gain */ + r = rtlsdr_set_tuner_gain_mode(dev, 1); + if (r < 0) + fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); + + /* Set the tuner gain */ + r = rtlsdr_set_tuner_gain(dev, gain); + if (r < 0) + fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); + else + fprintf(stderr, "Tuner gain set to %f dB.\n", gain / 10.0); + } + + r = rtlsdr_set_freq_correction(dev, ppm_error); - r = rtlsdr_set_freq_correction(dev, ppm_error); + } - demod->save_data = 1; - if (!filename) { - demod->save_data = 0; - } else if (strcmp(filename, "-") == 0) { /* Write samples to stdout */ - demod->file = stdout; + if (out_filename) { + if (strcmp(out_filename, "-") == 0) { /* Write samples to stdout */ + demod->out_file = stdout; #ifdef _WIN32 - _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdin), _O_BINARY); #endif - } else { - demod->file = fopen(filename, "wb"); - if (!demod->file) { - fprintf(stderr, "Failed to open %s\n", filename); - goto out; - } - } + } else { + if (access(out_filename, F_OK) == 0 && !overwrite_mode) { + fprintf(stderr, "Output file %s already exists, exiting\n", out_filename); + goto out; + } + demod->out_file = fopen(out_filename, "wb"); + if (!demod->out_file) { + fprintf(stderr, "Failed to open %s\n", out_filename); + goto out; + } + } + } if (demod->signal_grabber) demod->sg_buf = malloc(SIGNAL_GRABBER_BUFFER); - if (test_mode_file) { + if (in_filename) { int i = 0; unsigned char test_mode_buf[DEFAULT_BUF_LENGTH]; - fprintf(stderr, "Test mode active. Reading samples from file: %s\n", test_mode_file); - test_mode = fopen(test_mode_file, "r"); - if (!test_mode) { - fprintf(stderr, "Opening file: %s failed!\n", test_mode_file); - goto out; - } - while (fread(test_mode_buf, 131072, 1, test_mode) != 0) { - rtlsdr_callback(test_mode_buf, 131072, demod); + float test_mode_float_buf[DEFAULT_BUF_LENGTH]; + if (strcmp(in_filename, "-") == 0) { /* read samples from stdin */ + in_file = stdin; + in_filename = ""; + } else { + in_file = fopen(in_filename, "rb"); + if (!in_file) { + fprintf(stderr, "Opening file: %s failed!\n", in_filename); + goto out; + } + } + fprintf(stderr, "Test mode active. Reading samples from file: %s\n", in_filename); // Essential information (not quiet) + if (!quiet_mode) { + fprintf(stderr, "Input format: %s\n", (demod->debug_mode == 3) ? "cf32" : "uint8"); + } + sample_file_pos = 0.0; + + int n_read, cf32_tmp; + do { + if (demod->debug_mode == 3) { + n_read = fread(test_mode_float_buf, sizeof(float), 131072, in_file); + for(int n = 0; n < n_read; n++) { + cf32_tmp = test_mode_float_buf[n]*127 + 127; + if (cf32_tmp < 0) + cf32_tmp = 0; + else if (cf32_tmp > 255) + cf32_tmp = 255; + test_mode_buf[n] = (uint8_t)cf32_tmp; + } + } else { + n_read = fread(test_mode_buf, 1, 131072, in_file); + } + if (n_read == 0) break; // rtlsdr_callback() will Segmentation Fault with len=0 + rtlsdr_callback(test_mode_buf, n_read, demod); i++; - } + sample_file_pos = (float)i * n_read / samp_rate; + } 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 + rtlsdr_callback(test_mode_buf, 131072, demod); // Why the magic value 131072? + //Always classify a signal at the end of the file classify_signal(); - fprintf(stderr, "Test mode file issued %d packets\n", i); - fprintf(stderr, "Filter coeffs used:\n"); - fprintf(stderr, "a: %d %d\n", a[0], a[1]); - fprintf(stderr, "b: %d %d\n", b[0], b[1]); + if (!quiet_mode) { + fprintf(stderr, "Test mode file issued %d packets\n", i); + } exit(0); } @@ -1159,7 +1182,15 @@ int main(int argc, char **argv) { fprintf(stderr, "WARNING: Failed to reset buffers.\n"); if (sync_mode) { - fprintf(stderr, "Reading samples in sync mode...\n"); + if (!demod->out_file) { + fprintf(stderr, "Specify an output file for sync mode.\n"); + exit(0); + } + + fprintf(stderr, "Reading samples in sync mode...\n"); + uint8_t *buffer = malloc(out_block_size * sizeof (uint8_t)); + + time_t timestamp; while (!do_exit) { r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read); if (r < 0) { @@ -1172,7 +1203,7 @@ int main(int argc, char **argv) { do_exit = 1; } - if (fwrite(buffer, 1, n_read, demod->file) != (size_t) n_read) { + if (fwrite(buffer, 1, n_read, demod->out_file) != (size_t) n_read) { fprintf(stderr, "Short write, samples lost, exiting!\n"); break; } @@ -1182,9 +1213,19 @@ int main(int argc, char **argv) { break; } + if (duration > 0) { + time(×tamp); + if (timestamp >= stop_time) { + do_exit = 1; + fprintf(stderr, "Time expired, exiting!\n"); + } + } + if (bytes_to_read > 0) bytes_to_read -= n_read; } + + free(buffer); } else { if (frequencies == 0) { frequency[0] = DEFAULT_FREQUENCY; @@ -1192,7 +1233,9 @@ int main(int argc, char **argv) { } else { time(&rawtime_old); } - fprintf(stderr, "Reading samples in async mode...\n"); + if (!quiet_mode) { + fprintf(stderr, "Reading samples in async mode...\n"); + } while (!do_exit) { /* Set the frequency */ r = rtlsdr_set_center_freq(dev, frequency[frequency_current]); @@ -1213,8 +1256,8 @@ int main(int argc, char **argv) { else fprintf(stderr, "\nLibrary error %d, exiting...\n", r); - if (demod->file && (demod->file != stdout)) - fclose(demod->file); + if (demod->out_file && (demod->out_file != stdout)) + fclose(demod->out_file); for (i = 0; i < demod->r_dev_num; i++) free(demod->r_devs[i]); @@ -1222,11 +1265,14 @@ int main(int argc, char **argv) { if (demod->signal_grabber) free(demod->sg_buf); - if (demod) - free(demod); + free(demod); rtlsdr_close(dev); - free(buffer); out: + for (output_handler_t *output = output_handler; output; output = output->next) { + if (output->aux_free) { + output->aux_free(output->aux); + } + } return r >= 0 ? r : -r; }