void modesInitRTLSDR(void) { int j; int device_count; char vendor[256], product[256], serial[256]; device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "[dvbt][e]No supported RTLSDR devices found.\n"); exit(1); } fprintf(stderr, "[dvbt][i]Found %d device(s):\n", device_count); for (j = 0; j < device_count; j++) { rtlsdr_get_device_usb_strings(j, vendor, product, serial); fprintf(stderr, "[dvbt][i]%d: %s, %s, SN: %s %s\n", j, vendor, product, serial, (j == Modes.dev_index) ? "(currently selected)" : ""); } if (rtlsdr_open(&Modes.dev, Modes.dev_index) < 0) { fprintf(stderr, "[dvbt][e]Error opening the RTLSDR device: %s\n", strerror(errno)); exit(1); } /* Set gain, frequency, sample rate, and reset the device. */ rtlsdr_set_tuner_gain_mode(Modes.dev, (Modes.gain == MODES_AUTO_GAIN) ? 0 : 1); if (Modes.gain != MODES_AUTO_GAIN) { if (Modes.gain == MODES_MAX_GAIN) { /* Find the maximum gain available. */ int numgains; int gains[100]; numgains = rtlsdr_get_tuner_gains(Modes.dev, gains); Modes.gain = gains[numgains-1]; fprintf(stderr, "[dvbt][i]Max available gain is: %.2f\n", Modes.gain/10.0); } rtlsdr_set_tuner_gain(Modes.dev, Modes.gain); fprintf(stderr, "[dvbt][i]Setting gain to: %.2f\n", Modes.gain/10.0); } else { fprintf(stderr, "[dvbt][i]Using automatic gain control.\n"); } if( Modes.ppm_error != 0) { fprintf(stderr, "[dvbt][i]Setting ppm error to: %d\n", Modes.ppm_error); } rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error); if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1); rtlsdr_set_center_freq(Modes.dev, Modes.freq); rtlsdr_set_sample_rate(Modes.dev, MODES_DEFAULT_RATE); rtlsdr_reset_buffer(Modes.dev); fprintf(stderr, "[dvbt][i]Gain reported by device: %.2f\n", rtlsdr_get_tuner_gain(Modes.dev)/10.0); }
int rtlsdr_verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error) { int r; if (ppm_error == 0) { return 0;} r = rtlsdr_set_freq_correction(dev, ppm_error); if (r < 0) { fprintf(stderr, "WARNING: Failed to set ppm error.\n"); } else { fprintf(stderr, "Tuner error set to %i ppm.\n", ppm_error); } return r; }
int rtl_set_freq_correction(rtl r, int ppm_error) { int status; status = rtlsdr_set_freq_correction(r->device, ppm_error); if (status < 0) { ERROR("Failed to set ppm error.\n"); } else { DEBUG("Tuner error set to %i ppm.\n", ppm_error); } return status; }
int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; #endif struct fm_state fm; char *filename = NULL; int n_read, r, opt, wb_mode = 0; int i, gain = AUTO_GAIN; // tenths of a dB uint8_t *buffer; uint32_t dev_index = 0; int device_count; int ppm_error = 0; char vendor[256], product[256], serial[256]; fm_init(&fm); pthread_cond_init(&data_ready, NULL); pthread_rwlock_init(&data_rw, NULL); pthread_mutex_init(&data_mutex, NULL); while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:EFA:NWMULRDCh")) != -1) { switch (opt) { case 'd': dev_index = atoi(optarg); break; case 'f': if (fm.freq_len >= FREQUENCIES_LIMIT) { break;} if (strchr(optarg, ':')) {frequency_range(&fm, optarg);} else { fm.freqs[fm.freq_len] = (uint32_t)atofs(optarg); fm.freq_len++; } break; case 'g': gain = (int)(atof(optarg) * 10); break; case 'l': fm.squelch_level = (int)atof(optarg); break; case 's': fm.sample_rate = (uint32_t)atofs(optarg); break; case 'r': fm.output_rate = (int)atofs(optarg); break; case 'o': fm.post_downsample = (int)atof(optarg); if (fm.post_downsample < 1 || fm.post_downsample > MAXIMUM_OVERSAMPLE) { fprintf(stderr, "Oversample must be between 1 and %i\n", MAXIMUM_OVERSAMPLE);} break; case 't': fm.conseq_squelch = (int)atof(optarg); if (fm.conseq_squelch < 0) { fm.conseq_squelch = -fm.conseq_squelch; fm.terminate_on_squelch = 1; } break; case 'p': ppm_error = atoi(optarg); break; case 'E': fm.edge = 1; break; case 'F': fm.fir_enable = 1; break; case 'A': if (strcmp("std", optarg) == 0) { fm.custom_atan = 0;} if (strcmp("fast", optarg) == 0) { fm.custom_atan = 1;} if (strcmp("lut", optarg) == 0) { atan_lut_init(); fm.custom_atan = 2;} break; case 'D': fm.deemph = 1; break; case 'C': fm.dc_block = 1; break; case 'N': fm.mode_demod = &fm_demod; break; case 'W': wb_mode = 1; fm.mode_demod = &fm_demod; fm.sample_rate = 170000; fm.output_rate = 32000; fm.custom_atan = 1; fm.post_downsample = 4; fm.deemph = 1; fm.squelch_level = 0; break; case 'M': fm.mode_demod = &am_demod; break; case 'U': fm.mode_demod = &usb_demod; break; case 'L': fm.mode_demod = &lsb_demod; break; case 'R': fm.mode_demod = &raw_demod; break; case 'h': default: usage(); break; } } /* quadruple sample_rate to limit to Δθ to ±π/2 */ fm.sample_rate *= fm.post_downsample; if (fm.freq_len == 0) { fprintf(stderr, "Please specify a frequency.\n"); exit(1); } if (fm.freq_len >= FREQUENCIES_LIMIT) { fprintf(stderr, "Too many channels, maximum %i.\n", FREQUENCIES_LIMIT); exit(1); } if (fm.freq_len > 1 && fm.squelch_level == 0) { fprintf(stderr, "Please specify a squelch level. Required for scanning multiple frequencies.\n"); exit(1); } if (fm.freq_len > 1) { fm.terminate_on_squelch = 0; } if (argc <= optind) { filename = "-"; } else { filename = argv[optind]; } ACTUAL_BUF_LENGTH = lcm_post[fm.post_downsample] * DEFAULT_BUF_LENGTH; buffer = malloc(ACTUAL_BUF_LENGTH * sizeof(uint8_t)); device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported devices found.\n"); 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"); 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); 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); #else SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif /* WBFM is special */ // I really should loop over everything // but you are more wrong for scanning broadcast FM if (wb_mode) { fm.freqs[0] += 16000; } if (fm.deemph) { fm.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(fm.output_rate * 75e-6))))); } optimal_settings(&fm, 0, 0); build_fir(&fm); /* Set the tuner gain */ if (gain == AUTO_GAIN) { r = rtlsdr_set_tuner_gain_mode(dev, 0); } else { r = rtlsdr_set_tuner_gain_mode(dev, 1); gain = nearest_gain(gain); r = rtlsdr_set_tuner_gain(dev, gain); } if (r != 0) { fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); } else if (gain == AUTO_GAIN) { fprintf(stderr, "Tuner gain set to automatic.\n"); } else { fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0); } r = rtlsdr_set_freq_correction(dev, ppm_error); if (strcmp(filename, "-") == 0) { /* Write samples to stdout */ fm.file = stdout; #ifdef _WIN32 _setmode(_fileno(fm.file), _O_BINARY); #endif } else { fm.file = fopen(filename, "wb"); if (!fm.file) { fprintf(stderr, "Failed to open %s\n", filename); exit(1); } } /* Reset endpoint before we start reading from it (mandatory) */ r = rtlsdr_reset_buffer(dev); if (r < 0) { fprintf(stderr, "WARNING: Failed to reset buffers.\n");} pthread_create(&demod_thread, NULL, demod_thread_fn, (void *)(&fm)); /*rtlsdr_read_async(dev, rtlsdr_callback, (void *)(&fm), DEFAULT_ASYNC_BUF_NUMBER, ACTUAL_BUF_LENGTH);*/ while (!do_exit) { sync_read(buffer, ACTUAL_BUF_LENGTH, &fm); } while (!do_exit) { sync_read(buffer, ACTUAL_BUF_LENGTH, &fm); } if (do_exit) { fprintf(stderr, "\nUser cancel, exiting...\n");} else { fprintf(stderr, "\nLibrary error %d, exiting...\n", r);} //rtlsdr_cancel_async(dev); safe_cond_signal(&data_ready, &data_mutex); pthread_join(demod_thread, NULL); pthread_cond_destroy(&data_ready); pthread_rwlock_destroy(&data_rw); pthread_mutex_destroy(&data_mutex); if (fm.file != stdout) { fclose(fm.file);} rtlsdr_close(dev); free (buffer); return r >= 0 ? r : -r; }
// // =============================== RTLSDR handling ========================== // int modesInitRTLSDR(void) { int j; int device_count, dev_index = 0; char vendor[256], product[256], serial[256]; if (Modes.dev_name) { if ( (dev_index = verbose_device_search(Modes.dev_name)) < 0 ) return -1; } device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported RTLSDR devices found.\n"); return -1; } fprintf(stderr, "Found %d device(s):\n", device_count); for (j = 0; j < device_count; j++) { rtlsdr_get_device_usb_strings(j, vendor, product, serial); fprintf(stderr, "%d: %s, %s, SN: %s %s\n", j, vendor, product, serial, (j == dev_index) ? "(currently selected)" : ""); } if (rtlsdr_open(&Modes.dev, dev_index) < 0) { fprintf(stderr, "Error opening the RTLSDR device: %s\n", strerror(errno)); return -1; } // Set gain, frequency, sample rate, and reset the device rtlsdr_set_tuner_gain_mode(Modes.dev, (Modes.gain == MODES_AUTO_GAIN) ? 0 : 1); if (Modes.gain != MODES_AUTO_GAIN) { int *gains; int numgains; numgains = rtlsdr_get_tuner_gains(Modes.dev, NULL); if (numgains <= 0) { fprintf(stderr, "Error getting tuner gains\n"); return -1; } gains = malloc(numgains * sizeof(int)); if (rtlsdr_get_tuner_gains(Modes.dev, gains) != numgains) { fprintf(stderr, "Error getting tuner gains\n"); free(gains); return -1; } if (Modes.gain == MODES_MAX_GAIN) { int highest = -1; int i; for (i = 0; i < numgains; ++i) { if (gains[i] > highest) highest = gains[i]; } Modes.gain = highest; fprintf(stderr, "Max available gain is: %.2f dB\n", Modes.gain/10.0); } else { int closest = -1; int i; for (i = 0; i < numgains; ++i) { if (closest == -1 || abs(gains[i] - Modes.gain) < abs(closest - Modes.gain)) closest = gains[i]; } if (closest != Modes.gain) { Modes.gain = closest; fprintf(stderr, "Closest available gain: %.2f dB\n", Modes.gain/10.0); } } free(gains); fprintf(stderr, "Setting gain to: %.2f dB\n", Modes.gain/10.0); if (rtlsdr_set_tuner_gain(Modes.dev, Modes.gain) < 0) { fprintf(stderr, "Error setting tuner gains\n"); return -1; } } else { fprintf(stderr, "Using automatic gain control.\n"); } rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error); if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1); rtlsdr_set_center_freq(Modes.dev, Modes.freq); rtlsdr_set_sample_rate(Modes.dev, (unsigned)Modes.sample_rate); rtlsdr_reset_buffer(Modes.dev); fprintf(stderr, "Gain reported by device: %.2f dB\n", rtlsdr_get_tuner_gain(Modes.dev)/10.0); return 0; }
int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; #endif char *out_filename = NULL; char *in_filename = NULL; FILE *in_file; int n_read; int r = 0, opt; int i, gain = 0; int sync_mode = 0; int ppm_error = 0; struct dm_state* demod; 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; setbuf(stdout, NULL); setbuf(stderr, NULL); demod = malloc(sizeof (struct dm_state)); memset(demod, 0, sizeof (struct dm_state)); /* initialize tables */ baseband_init(); 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:DtaAqm:r:l:d:f:g:s:b:n:SR:F:C:T:UW")) != -1) { switch (opt) { case 'd': dev_index = atoi(optarg); break; case 'f': if (frequencies < MAX_PROTOCOLS) frequency[frequencies++] = (uint32_t) atof(optarg); else fprintf(stderr, "Max number of frequencies reached %d\n", MAX_PROTOCOLS); break; case 'g': gain = (int) (atof(optarg) * 10); /* tenths of a dB */ break; case 'p': ppm_error = atoi(optarg); break; case 's': samp_rate = (uint32_t) atof(optarg); break; case 'b': out_block_size = (uint32_t) atof(optarg); break; case 'l': demod->level_limit = (uint32_t) atof(optarg); break; case 'n': bytes_to_read = (uint32_t) atof(optarg) * 2; break; case 'a': demod->analyze = 1; break; case 'A': demod->analyze_pulses = 1; break; case 'r': in_filename = optarg; break; case 't': demod->signal_grabber = 1; break; case 'm': demod->debug_mode = atoi(optarg); break; case 'S': sync_mode = 1; break; case 'D': debug_output++; break; case 'z': override_short = atoi(optarg); break; 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(devices); break; } } if (argc <= optind - 1) { usage(devices); } else { out_filename = argv[optind]; } if (!output_handler) { add_kv_output(); } for (i = 0; i < num_r_devices; i++) { if (!devices[i].disabled) { register_protocol(demod, &devices[i]); if(devices[i].modulation >= FSK_DEMOD_MIN_VAL) { demod->enable_FM_demod = 1; } } } if (out_block_size < MINIMAL_BUF_LENGTH || out_block_size > MAXIMAL_BUF_LENGTH) { fprintf(stderr, "Output block size wrong value, falling back to default\n"); fprintf(stderr, "Minimal length: %u\n", MINIMAL_BUF_LENGTH); fprintf(stderr, "Maximal length: %u\n", MAXIMAL_BUF_LENGTH); out_block_size = DEFAULT_BUF_LENGTH; } if (!in_filename) { device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported devices found.\n"); if (!in_filename) exit(1); } 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)); } 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); #else 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, "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); } r = rtlsdr_set_freq_correction(dev, ppm_error); } if (out_filename) { if (strcmp(out_filename, "-") == 0) { /* Write samples to stdout */ demod->out_file = stdout; #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif } 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 (in_filename) { int i = 0; unsigned char test_mode_buf[DEFAULT_BUF_LENGTH]; float test_mode_float_buf[DEFAULT_BUF_LENGTH]; if (strcmp(in_filename, "-") == 0) { /* read samples from stdin */ in_file = stdin; in_filename = "<stdin>"; } 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(); if (!quiet_mode) { fprintf(stderr, "Test mode file issued %d packets\n", i); } exit(0); } /* Reset endpoint before we start reading from it (mandatory) */ r = rtlsdr_reset_buffer(dev); if (r < 0) fprintf(stderr, "WARNING: Failed to reset buffers.\n"); if (sync_mode) { 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) { fprintf(stderr, "WARNING: sync read failed.\n"); break; } if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t) n_read)) { n_read = bytes_to_read; do_exit = 1; } if (fwrite(buffer, 1, n_read, demod->out_file) != (size_t) n_read) { fprintf(stderr, "Short write, samples lost, exiting!\n"); break; } if ((uint32_t) n_read < out_block_size) { fprintf(stderr, "Short read, samples lost, exiting!\n"); 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; frequencies = 1; } else { time(&rawtime_old); } 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]); if (r < 0) fprintf(stderr, "WARNING: Failed to set center freq.\n"); else fprintf(stderr, "Tuned to %u Hz.\n", rtlsdr_get_center_freq(dev)); r = rtlsdr_read_async(dev, rtlsdr_callback, (void *) demod, DEFAULT_ASYNC_BUF_NUMBER, out_block_size); do_exit_async = 0; frequency_current++; if (frequency_current > frequencies - 1) frequency_current = 0; } } if (do_exit) fprintf(stderr, "\nUser cancel, exiting...\n"); else fprintf(stderr, "\nLibrary error %d, exiting...\n", r); 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]); if (demod->signal_grabber) free(demod->sg_buf); free(demod); rtlsdr_close(dev); 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; }
void dabStick::setCorrection (int ppm) { if (!open || !libraryLoaded) return; rtlsdr_set_freq_correction (device, ppm); }
bool CRtlSdr::open() { if (device_count == 0) { qDebug() << "No supported device found to open rtlsdr device " << dongle.dev_index << "\n"; power = false; return false; } Initialize(&dongle,&demod); dongle.dev_index = 0; if (dongle.dev_index < 0) { power = false; return false; } int r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index); if (r < 0) { qDebug() << "Failed to open rtlsdr device " << dongle.dev_index << "\n"; power = false; return false; } r = rtlsdr_set_tuner_gain_mode(dongle.dev,dongle.gain); if (r < 0) { qDebug() << "Failed to set gain to " << dongle.gain << "\n"; power = false; return false; } r = rtlsdr_set_tuner_gain(dongle.dev,20); if (r < 0) { qDebug() << "Failed to set gain to " << dongle.gain << "\n"; power = false; return false; } r = rtlsdr_reset_buffer(dongle.dev); if (r < 0) { qDebug() << "WARNING: Failed to reset buffers.\n"; } r = rtlsdr_set_sample_rate(dongle.dev,dongle.rate); if (r < 0) { qDebug() << "Failed to set sample rate to " << dongle.rate << "\n"; power = false; return false; } r = rtlsdr_set_freq_correction(dongle.dev,43); if (r < 0) { qDebug() << "Failed to set ppm rate to " << 43 << "\n"; power = false; return false; } qDebug() << "Dongle sample rate " << rtlsdr_get_sample_rate(dongle.dev); // Build a data reader thead pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(this)); power = true; log_t.isConnected = true; return true; }
int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; #endif char *filename = NULL; int i, length, n_read, r, opt, wb_mode = 0; int f_set = 0; int gain = AUTO_GAIN; // tenths of a dB uint8_t *buffer; uint32_t dev_index = 0; int device_count; int ppm_error = 0; int interval = 10; int fft_threads = 1; int smoothing = 0; int single = 0; double crop = 0.0; char vendor[256], product[256], serial[256]; char *freq_optarg; time_t next_tick; time_t time_now; time_t exit_time = 0; char t_str[50]; struct tm *cal_time; double (*window_fn)(int, int) = rectangle; freq_optarg = ""; while ((opt = getopt(argc, argv, "f:i:s:t:d:g:p:e:w:c:1Fh")) != -1) { switch (opt) { case 'f': // lower:upper:bin_size freq_optarg = strdup(optarg); f_set = 1; break; case 'd': dev_index = atoi(optarg); break; case 'g': gain = (int)(atof(optarg) * 10); break; case 'c': crop = atofp(optarg); break; case 'i': interval = (int)round(atoft(optarg)); break; case 'e': exit_time = (time_t)((int)round(atoft(optarg))); break; case 's': if (strcmp("avg", optarg) == 0) { smoothing = 0;} if (strcmp("iir", optarg) == 0) { smoothing = 1;} break; case 'w': if (strcmp("rectangle", optarg) == 0) { window_fn = rectangle;} if (strcmp("hamming", optarg) == 0) { window_fn = hamming;} if (strcmp("blackman", optarg) == 0) { window_fn = blackman;} if (strcmp("blackman-harris", optarg) == 0) { window_fn = blackman_harris;} if (strcmp("hann-poisson", optarg) == 0) { window_fn = hann_poisson;} if (strcmp("youssef", optarg) == 0) { window_fn = youssef;} if (strcmp("kaiser", optarg) == 0) { window_fn = kaiser;} if (strcmp("bartlett", optarg) == 0) { window_fn = bartlett;} break; case 't': fft_threads = atoi(optarg); break; case 'p': ppm_error = atoi(optarg); break; case '1': single = 1; break; case 'F': boxcar = 0; break; case 'h': default: usage(); break; } } if (!f_set) { fprintf(stderr, "No frequency range provided.\n"); exit(1); } if ((crop < 0.0) || (crop > 1.0)) { fprintf(stderr, "Crop value outside of 0 to 1.\n"); exit(1); } frequency_range(freq_optarg, crop); if (tune_count == 0) { usage();} if (argc <= optind) { filename = "-"; } else { filename = argv[optind]; } if (interval < 1) { interval = 1;} fprintf(stderr, "Reporting every %i seconds\n", interval); device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported devices found.\n"); 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"); 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); 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); #else SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif /* Set the tuner gain */ if (gain == AUTO_GAIN) { r = rtlsdr_set_tuner_gain_mode(dev, 0); } else { r = rtlsdr_set_tuner_gain_mode(dev, 1); gain = nearest_gain(gain); r = rtlsdr_set_tuner_gain(dev, gain); } if (r != 0) { fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); } else if (gain == AUTO_GAIN) { fprintf(stderr, "Tuner gain set to automatic.\n"); } else { fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0); } r = rtlsdr_set_freq_correction(dev, ppm_error); if (strcmp(filename, "-") == 0) { /* Write log to stdout */ file = stdout; #ifdef _WIN32 // Is this necessary? Output is ascii. _setmode(_fileno(file), _O_BINARY); #endif } else { file = fopen(filename, "wb"); if (!file) { fprintf(stderr, "Failed to open %s\n", filename); exit(1); } } /* Reset endpoint before we start reading from it (mandatory) */ r = rtlsdr_reset_buffer(dev); if (r < 0) { fprintf(stderr, "WARNING: Failed to reset buffers.\n");} /* actually do stuff */ rtlsdr_set_sample_rate(dev, (uint32_t)tunes[0].rate); sine_table(tunes[0].bin_e); next_tick = time(NULL) + interval; if (exit_time) { exit_time = time(NULL) + exit_time;} fft_buf = malloc(tunes[0].buf_len * sizeof(int16_t)); length = 1 << tunes[0].bin_e; window_coefs = malloc(length * sizeof(int)); for (i=0; i<length; i++) { window_coefs[i] = (int)(256*window_fn(i, length)); } while (!do_exit) { scanner(); time_now = time(NULL); if (time_now < next_tick) { continue;} // time, Hz low, Hz high, Hz step, samples, dbm, dbm, ... cal_time = localtime(&time_now); strftime(t_str, 50, "%Y-%m-%d, %H:%M:%S", cal_time); for (i=0; i<tune_count; i++) { fprintf(file, "%s, ", t_str); csv_dbm(&tunes[i]); } fflush(file); while (time(NULL) >= next_tick) { next_tick += interval;} if (single) { do_exit = 1;} if (exit_time && time(NULL) >= exit_time) { do_exit = 1;} } /* clean up */ if (do_exit) { fprintf(stderr, "\nUser cancel, exiting...\n");} else { fprintf(stderr, "\nLibrary error %d, exiting...\n", r);} if (file != stdout) { fclose(file);} rtlsdr_close(dev); free(fft_buf); free(window_coefs); //for (i=0; i<tune_count; i++) { // free(tunes[i].avg); // free(tunes[i].buf8); //} return r >= 0 ? r : -r; }
int main(int argc, char** argv) { uint32_t opt; int32_t rtl_result; int32_t rtl_count; char rtl_vendor[256], rtl_product[256], rtl_serial[256]; initrx_options(); initDecoder_options(); /* RX buffer allocation */ rx_state.iSamples=malloc(sizeof(float)*SIGNAL_LENGHT*SIGNAL_SAMPLE_RATE); rx_state.qSamples=malloc(sizeof(float)*SIGNAL_LENGHT*SIGNAL_SAMPLE_RATE); /* Stop condition setup */ rx_state.exit_flag = false; rx_state.decode_flag = false; uint32_t nLoop = 0; if (argc <= 1) usage(); while ((opt = getopt(argc, argv, "f:c:l:g:a:o:p:u:d:n:i:H:Q:S")) != -1) { switch (opt) { case 'f': // Frequency rx_options.dialfreq = (uint32_t)atofs(optarg); break; case 'c': // Callsign sprintf(dec_options.rcall, "%.12s", optarg); break; case 'l': // Locator / Grid sprintf(dec_options.rloc, "%.6s", optarg); break; case 'g': // Small signal amplifier gain rx_options.gain = atoi(optarg); if (rx_options.gain < 0) rx_options.gain = 0; if (rx_options.gain > 49) rx_options.gain = 49; rx_options.gain *= 10; break; case 'a': // Auto gain rx_options.autogain = atoi(optarg); if (rx_options.autogain < 0) rx_options.autogain = 0; if (rx_options.autogain > 1) rx_options.autogain = 1; break; case 'o': // Fine frequency correction rx_options.shift = atoi(optarg); break; case 'p': rx_options.ppm = atoi(optarg); break; case 'u': // Upconverter frequency rx_options.upconverter = (uint32_t)atofs(optarg); break; case 'd': // Direct Sampling rx_options.directsampling = (uint32_t)atofs(optarg); break; case 'n': // Stop after n iterations rx_options.maxloop = (uint32_t)atofs(optarg); break; case 'i': // Select the device to use rx_options.device = (uint32_t)atofs(optarg); break; case 'H': // Decoder option, use a hastable dec_options.usehashtable = 1; break; case 'Q': // Decoder option, faster dec_options.quickmode = 1; break; case 'S': // Decoder option, single pass mode (same as original wsprd) dec_options.subtraction = 0; dec_options.npasses = 1; break; default: usage(); break; } } if (rx_options.dialfreq == 0) { fprintf(stderr, "Please specify a dial frequency.\n"); fprintf(stderr, " --help for usage...\n"); exit(1); } if (dec_options.rcall[0] == 0) { fprintf(stderr, "Please specify your callsign.\n"); fprintf(stderr, " --help for usage...\n"); exit(1); } if (dec_options.rloc[0] == 0) { fprintf(stderr, "Please specify your locator.\n"); fprintf(stderr, " --help for usage...\n"); exit(1); } /* Calcule shift offset */ rx_options.realfreq = rx_options.dialfreq + rx_options.shift + rx_options.upconverter; /* Store the frequency used for the decoder */ dec_options.freq = rx_options.dialfreq; /* If something goes wrong... */ signal(SIGINT, &sigint_callback_handler); signal(SIGTERM, &sigint_callback_handler); signal(SIGILL, &sigint_callback_handler); signal(SIGFPE, &sigint_callback_handler); signal(SIGSEGV, &sigint_callback_handler); signal(SIGABRT, &sigint_callback_handler); /* Init & parameter the device */ rtl_count = rtlsdr_get_device_count(); if (!rtl_count) { fprintf(stderr, "No supported devices found\n"); return EXIT_FAILURE; } fprintf(stderr, "Found %d device(s):\n", rtl_count); for (uint32_t i=0; i<rtl_count; i++) { rtlsdr_get_device_usb_strings(i, rtl_vendor, rtl_product, rtl_serial); fprintf(stderr, " %d: %s, %s, SN: %s\n", i, rtl_vendor, rtl_product, rtl_serial); } fprintf(stderr, "\nUsing device %d: %s\n", rx_options.device, rtlsdr_get_device_name(rx_options.device)); rtl_result = rtlsdr_open(&rtl_device, rx_options.device); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to open rtlsdr device #%d.\n", rx_options.device); return EXIT_FAILURE; } if (rx_options.directsampling) { rtl_result = rtlsdr_set_direct_sampling(rtl_device, rx_options.directsampling); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to set direct sampling\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } } rtl_result = rtlsdr_set_sample_rate(rtl_device, SAMPLING_RATE); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to set sample rate\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } rtl_result = rtlsdr_set_tuner_gain_mode(rtl_device, 1); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to enable manual gain\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } if (rx_options.autogain) { rtl_result = rtlsdr_set_tuner_gain_mode(rtl_device, 0); if (rtl_result != 0) { fprintf(stderr, "ERROR: Failed to set tuner gain\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } } else { rtl_result = rtlsdr_set_tuner_gain(rtl_device, rx_options.gain); if (rtl_result != 0) { fprintf(stderr, "ERROR: Failed to set tuner gain\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } } if (rx_options.ppm != 0) { rtl_result = rtlsdr_set_freq_correction(rtl_device, rx_options.ppm); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to set ppm error\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } } rtl_result = rtlsdr_set_center_freq(rtl_device, rx_options.realfreq + FS4_RATE + 1500); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to set frequency\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } rtl_result = rtlsdr_reset_buffer(rtl_device); if (rtl_result < 0) { fprintf(stderr, "ERROR: Failed to reset buffers.\n"); rtlsdr_close(rtl_device); return EXIT_FAILURE; } /* Print used parameter */ time_t rawtime; time ( &rawtime ); struct tm *gtm = gmtime(&rawtime); printf("\nStarting rtlsdr-wsprd (%04d-%02d-%02d, %02d:%02dz) -- Version 0.2\n", gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday, gtm->tm_hour, gtm->tm_min); printf(" Callsign : %s\n", dec_options.rcall); printf(" Locator : %s\n", dec_options.rloc); printf(" Dial freq. : %d Hz\n", rx_options.dialfreq); printf(" Real freq. : %d Hz\n", rx_options.realfreq); printf(" PPM factor : %d\n", rx_options.ppm); if(rx_options.autogain) printf(" Auto gain : enable\n"); else printf(" Gain : %d dB\n", rx_options.gain/10); /* Time alignment stuff */ struct timeval lTime; gettimeofday(&lTime, NULL); uint32_t sec = lTime.tv_sec % 120; uint32_t usec = sec * 1000000 + lTime.tv_usec; uint32_t uwait = 120000000 - usec; printf("Wait for time sync (start in %d sec)\n\n", uwait/1000000); /* Prepare a low priority param for the decoder thread */ struct sched_param param; pthread_attr_init(&dec.tattr); pthread_attr_setschedpolicy(&dec.tattr, SCHED_RR); pthread_attr_getschedparam(&dec.tattr, ¶m); param.sched_priority = 90; // = sched_get_priority_min(); pthread_attr_setschedparam(&dec.tattr, ¶m); /* Create a thread and stuff for separate decoding Info : https://computing.llnl.gov/tutorials/pthreads/ */ pthread_rwlock_init(&dec.rw, NULL); pthread_cond_init(&dec.ready_cond, NULL); pthread_mutex_init(&dec.ready_mutex, NULL); pthread_create(&dongle.thread, NULL, rtlsdr_rx, NULL); pthread_create(&dec.thread, &dec.tattr, wsprDecoder, NULL); /* Main loop : Wait, read, decode */ while (!rx_state.exit_flag && !(rx_options.maxloop && (nLoop >= rx_options.maxloop))) { /* Wait for time Sync on 2 mins */ gettimeofday(&lTime, NULL); sec = lTime.tv_sec % 120; usec = sec * 1000000 + lTime.tv_usec; uwait = 120000000 - usec + 10000; // Adding 10ms, to be sure to reach this next minute usleep(uwait); //printf("SYNC! RX started\n"); /* Use the Store the date at the begin of the frame */ time ( &rawtime ); gtm = gmtime(&rawtime); sprintf(rx_options.date,"%02d%02d%02d", gtm->tm_year - 100, gtm->tm_mon + 1, gtm->tm_mday); sprintf(rx_options.uttime,"%02d%02d", gtm->tm_hour, gtm->tm_min); /* Start to store the samples */ initSampleStorage(); while( (rx_state.exit_flag == false) && (rx_state.iqIndex < (SIGNAL_LENGHT * SIGNAL_SAMPLE_RATE) ) ) { usleep(250000); } nLoop++; } /* Stop the RX and free the blocking function */ rtlsdr_cancel_async(rtl_device); /* Close the RTL device */ rtlsdr_close(rtl_device); printf("Bye!\n"); /* Wait the thread join (send a signal before to terminate the job) */ pthread_mutex_lock(&dec.ready_mutex); pthread_cond_signal(&dec.ready_cond); pthread_mutex_unlock(&dec.ready_mutex); pthread_join(dec.thread, NULL); pthread_join(dongle.thread, NULL); /* Destroy the lock/cond/thread */ pthread_rwlock_destroy(&dec.rw); pthread_cond_destroy(&dec.ready_cond); pthread_mutex_destroy(&dec.ready_mutex); pthread_exit(NULL); return EXIT_SUCCESS; }