X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/337eb4ba945097205fbb6a3ca7912fb0697092d1..refs/heads/master:/src/rtl_433.c?ds=inline
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;
}