// Part of dump1090, a Mode S message decoder for RTLSDR devices. // // sdr_hackrf.h: HackRF One support (header) // // Copyright (c) 2019 FlightAware LLC // // This file is free software: you may copy, redistribute and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation, either version 2 of the License, or (at your // option) any later version. // // This file is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "dump1090.h" #include "sdr_hackrf.h" #include #include static struct { hackrf_device *device; uint64_t freq; int enable_amp; int enable_ant_pwr; int lna_gain; int vga_gain; int rate; int ppm; iq_convert_fn converter; struct converter_state *converter_state; } HackRF; void hackRFInitConfig() { HackRF.device = NULL; HackRF.freq = 1090000000; HackRF.enable_amp = 0; HackRF.enable_ant_pwr = 0; HackRF.lna_gain = 32; HackRF.vga_gain = 50; HackRF.rate = 2400000; HackRF.ppm = 0; HackRF.converter = NULL; HackRF.converter_state = NULL; } bool hackRFHandleOption(int argc, char **argv, int *jptr) { int j = *jptr; bool more = (j+1 < argc); if (!strcmp(argv[j], "--lna-gain") && more) { HackRF.lna_gain = atoi(argv[++j]); if (HackRF.lna_gain % 8 != 0) { fprintf(stderr, "Error: --lna-gain must be multiple of 8\n"); return false; } if (HackRF.lna_gain > 40 || HackRF.lna_gain < 0) { fprintf(stderr, "Error: --lna-gain range is 0 - 42\n"); return false; } } else if (!strcmp(argv[j], "--vga-gain") && more) { HackRF.vga_gain = atoi(argv[++j]); if (HackRF.vga_gain % 2 != 0) { fprintf(stderr, "Error: --vga-gain must be multiple of 2\n"); return false; } if (HackRF.vga_gain > 62 || HackRF.vga_gain < 0) { fprintf(stderr, "Error: --vga-gain range is 0 - 62\n"); return false; } } else if (!strcmp(argv[j], "--ppm") && more) { HackRF.ppm = atoi(argv[++j]); } else if (!strcmp(argv[j], "--samplerate") && more) { HackRF.rate = atoi(argv[++j]); } else if (!strcmp(argv[j], "--enable-amp")) { HackRF.enable_amp = 1; } else if (!strcmp(argv[j], "--enable-antenna-power")) { HackRF.enable_ant_pwr = 1; } else { return false; } *jptr = j; return true; } void hackRFShowHelp() { printf(" HackRF-specific options (use with --device-type hackrf)\n"); printf("\n"); printf("--enable-amp enable amplifier)\n"); printf("--enable-antenna-power enable DC power to the antenna connector\n"); printf("--lna-gain set LNA gain (Range 0-40 in 8dB steps))\n"); printf("--vga-gain set VGA gain (Range 0-62 in 2dB steps))\n"); printf("--samplerate set sample rate)\n"); printf("--ppm ppm correction)\n"); printf("\n"); } static void show_config() { fprintf(stderr, "freq : %" PRIu64 "\n", HackRF.freq); fprintf(stderr, "lna_gain : %d\n", HackRF.lna_gain); fprintf(stderr, "vga_gain : %d\n", HackRF.vga_gain); fprintf(stderr, "samplerate : %d\n", HackRF.rate); fprintf(stderr, "ppm : %d\n", HackRF.ppm); } bool hackRFOpen() { if (HackRF.device) { return true; } // Calculate sample rate and frequency deviation if ppm is specified if (HackRF.ppm != 0) { HackRF.rate = (uint32_t)((double)HackRF.rate * (1000000 - HackRF.ppm)/1000000+0.5); HackRF.freq = HackRF.freq * (1000000 - HackRF.ppm)/1000000; } int status; status = hackrf_init(); if (status != 0) { fprintf(stderr, "HackRF: hackrf_init failed with code %d\n", status); return false; } status = hackrf_open(&HackRF.device); if (status != 0) { fprintf(stderr, "HackRF: hackrf_open failed with code %d\n", status); hackrf_exit(); return false; } status = hackrf_set_freq(HackRF.device, HackRF.freq); if (status != 0) { fprintf(stderr, "HackRF: hackrf_set_freq failed with code %d\n", status); hackrf_close(HackRF.device); hackrf_exit(); return false; } status = hackrf_set_sample_rate(HackRF.device, HackRF.rate); if (status != 0) { fprintf(stderr, "HackRF: hackrf_set_sample_rate failed with code %d\n", status); hackrf_close(HackRF.device); hackrf_exit(); return false; } status = hackrf_set_amp_enable(HackRF.device, HackRF.enable_amp); if (status != 0) { fprintf(stderr, "HackRF: hackrf_set_amp_enable failed with code %d\n", status); hackrf_close(HackRF.device); hackrf_exit(); return false; } status = hackrf_set_lna_gain(HackRF.device, HackRF.lna_gain); if (status != 0) { fprintf(stderr, "HackRF: hackrf_set_lna_gain failed with code %d\n", status); hackrf_close(HackRF.device); hackrf_exit(); return false; } status = hackrf_set_vga_gain(HackRF.device, HackRF.vga_gain); if (status != 0) { fprintf(stderr, "HackRF: hackrf_set_vga_gain failed with code %d\n", status); hackrf_close(HackRF.device); hackrf_exit(); return false; } status = hackrf_set_antenna_enable(HackRF.device, HackRF.enable_ant_pwr); if (status != 0) { fprintf(stderr, "HackRF: hackrf_set_antenna_enable failed with code %d\n", status); hackrf_close(HackRF.device); hackrf_exit(); return false; } show_config(); HackRF.converter = init_converter(INPUT_UC8, Modes.sample_rate, Modes.dc_filter, &HackRF.converter_state); if (!HackRF.converter) { fprintf(stderr, "HackRF: can't initialize sample converter\n"); return false; } return true; } static int handle_hackrf_samples(hackrf_transfer *transfer) { static unsigned dropped = 0; static uint64_t sampleCounter = 0; sdrMonitor(); if (Modes.exit || transfer->valid_length < 0) return -1; uint8_t *buf = transfer->buffer; unsigned len = transfer->valid_length; // Values returned by HackRF need conversion from signed to unsigned for (unsigned i = 0; i < len; i++) { buf[i] ^= (uint8_t)0x80; } unsigned samples_read = len / 2; // Drops any trailing odd sample, that's OK struct mag_buf *outbuf = fifo_acquire(0 /* don't wait */); if (!outbuf) { // FIFO is full. Drop this block. dropped += samples_read; sampleCounter += samples_read; return 0; } outbuf->flags = 0; if (dropped) { // We previously dropped some samples due to no buffers being available outbuf->flags |= MAGBUF_DISCONTINUOUS; outbuf->dropped = dropped; } dropped = 0; // Compute the sample timestamp and system timestamp for the start of the block outbuf->sampleTimestamp = sampleCounter * 12e6 / Modes.sample_rate; sampleCounter += samples_read; // Get the approx system time for the start of this block uint64_t block_duration = 1e3 * samples_read / Modes.sample_rate; outbuf->sysTimestamp = mstime() - block_duration; // Convert the new data unsigned to_convert = samples_read; if (to_convert + outbuf->overlap > outbuf->totalLength) { // how did that happen? to_convert = outbuf->totalLength - outbuf->overlap; dropped = samples_read - to_convert; } HackRF.converter(buf, &outbuf->data[outbuf->overlap], to_convert, HackRF.converter_state, &outbuf->mean_level, &outbuf->mean_power); outbuf->validLength = outbuf->overlap + to_convert; // Push to the demodulation thread fifo_enqueue(outbuf); return 0; } void hackRFRun() { if (!HackRF.device) { fprintf(stderr, "hackRFRun: HackRF.device = NULL\n"); return; } int status = hackrf_start_rx(HackRF.device, &handle_hackrf_samples, NULL); if (status != 0) { fprintf(stderr, "hackrf_start_rx failed\n"); hackrf_close(HackRF.device); hackrf_exit(); exit (1); } // hackrf_start_rx does not block so we need to wait until the streaming is finished // before returning from the hackRFRun function while (hackrf_is_streaming(HackRF.device) == HACKRF_TRUE) { struct timespec slp = { 0, 100 * 1000 * 1000}; nanosleep(&slp, NULL); } fprintf(stderr, "HackRF stopped streaming %d\n", hackrf_is_streaming(HackRF.device)); } void hackRFClose() { if (HackRF.device) { hackrf_close(HackRF.device); hackrf_exit(); HackRF.device = NULL; } }