diff --git a/Makefile b/Makefile
index 6343ffb..46d0c3c 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@ PROGNAME=dump1090
RTLSDR ?= yes
BLADERF ?= yes
+HACKRF ?= yes
CPPFLAGS += -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
@@ -39,6 +40,13 @@ ifeq ($(BLADERF), yes)
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
endif
+ifeq ($(HACKRF), yes)
+ SDR_OBJ += sdr_hackrf.o
+ CPPFLAGS += -DENABLE_HACKRF
+ CFLAGS += $(shell pkg-config --cflags libhackrf)
+ LIBS_SDR += $(shell pkg-config --libs libhackrf)
+endif
+
all: dump1090 view1090
%.o: %.c *.h
diff --git a/README.md b/README.md
index 31864c4..b578de8 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,10 @@ see https://flightaware.com/adsb/piaware/install
This is packaged with jessie. `sudo apt-get install librtlsdr-dev`
+### Dependencies - HackRF
+
+This is packaged with jessie. `sudo apt-get install libhackrf-dev`
+
### Actually building it
Nothing special, just build it (`dpkg-buildpackage -b`)
@@ -45,7 +49,7 @@ Nothing special, just build it (`dpkg-buildpackage -b`)
First run `prepare-wheezy-tree.sh`. This will create a package tree in
package-wheezy/. Build in there (`dpkg-buildpackage -b`)
-The wheezy build does not include bladeRF support.
+The wheezy build does not include bladeRF nor HackRF support.
## Building manually
@@ -58,3 +62,6 @@ libbladeRF.
``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on
librtlsdr.
+
+``make HACKRF=no`` will disable HackRF support and remove the dependency on
+libhackrf.
\ No newline at end of file
diff --git a/dump1090.c b/dump1090.c
index b654c01..88e8194 100644
--- a/dump1090.c
+++ b/dump1090.c
@@ -267,6 +267,9 @@ void showHelp(void) {
#ifdef ENABLE_BLADERF
"ENABLE_BLADERF "
#endif
+#ifdef ENABLE_HACKRF
+ "ENABLE_HACKRF "
+#endif
#ifdef SC16Q11_TABLE_BITS
// This is a little silly, but that's how the preprocessor works..
#define _stringize(x) #x
diff --git a/dump1090.h b/dump1090.h
index 90700ce..6bf2f62 100644
--- a/dump1090.h
+++ b/dump1090.h
@@ -279,7 +279,7 @@ typedef enum {
//======================== structure declarations =========================
typedef enum {
- SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF
+ SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_HACKRF
} sdr_type_t;
// Structure representing one magnitude buffer
diff --git a/sdr.c b/sdr.c
index 89fe8f4..569bc9a 100644
--- a/sdr.c
+++ b/sdr.c
@@ -27,6 +27,9 @@
#ifdef ENABLE_BLADERF
# include "sdr_bladerf.h"
#endif
+#ifdef ENABLE_HACKRF
+# include "sdr_hackrf.h"
+#endif
typedef struct {
const char *name;
@@ -85,6 +88,10 @@ static sdr_handler sdr_handlers[] = {
{ "bladerf", SDR_BLADERF, bladeRFInitConfig, bladeRFShowHelp, bladeRFHandleOption, bladeRFOpen, bladeRFRun, bladeRFClose },
#endif
+#ifdef ENABLE_HACKRF
+ { "hackrf", SDR_HACKRF, hackRFInitConfig, hackRFShowHelp, hackRFHandleOption, hackRFOpen, hackRFRun, hackRFClose },
+#endif
+
{ "ifile", SDR_IFILE, ifileInitConfig, ifileShowHelp, ifileHandleOption, ifileOpen, ifileRun, ifileClose },
{ "none", SDR_NONE, noInitConfig, noShowHelp, noHandleOption, noOpen, noRun, noClose },
diff --git a/sdr_hackrf.c b/sdr_hackrf.c
new file mode 100644
index 0000000..3a1ad98
--- /dev/null
+++ b/sdr_hackrf.c
@@ -0,0 +1,322 @@
+// 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 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.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) {
+ printf("Error: --lna-gain must be multiple of 8\n");
+ return false;
+ }
+
+ if (HackRF.lna_gain > 40 || HackRF.lna_gain < 0) {
+ printf("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) {
+ printf("Error: --vga-gain must be multiple of 2\n");
+ return false;
+ }
+
+ if (HackRF.vga_gain > 62 || HackRF.vga_gain < 0) {
+ printf("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") && more) {
+ HackRF.enable_amp = 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("--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()
+{
+ printf("freq : %ld\n", HackRF.freq);
+ printf("lna_gain : %d\n", HackRF.lna_gain);
+ printf("vga_gain : %d\n", HackRF.vga_gain);
+ printf("samplerate : %d\n", HackRF.rate);
+ printf("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) {
+ printf("HackRF: hackrf_init failed with code %d", status);
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ return false;
+ }
+
+ status = hackrf_open(&HackRF.device);
+ if (status != 0) {
+ printf("HackRF: hackrf_open failed with code %d", status);
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ return false;
+ }
+
+ status = hackrf_set_freq(HackRF.device, HackRF.freq);
+ if (status != 0) {
+ printf("HackRF: hackrf_set_freq failed with code %d", status);
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ return false;
+ }
+
+ status = hackrf_set_sample_rate(HackRF.device, HackRF.rate);
+ if (status != 0) {
+ printf("HackRF: hackrf_set_sample_rate failed with code %d", status);
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ return false;
+ }
+
+ status = hackrf_set_amp_enable(HackRF.device, HackRF.enable_amp);
+ if (status != 0) {
+ printf("HackRF: hackrf_set_amp_enable failed with code %d", status);
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ return false;
+ }
+
+ status = hackrf_set_lna_gain(HackRF.device, HackRF.lna_gain);
+ if (status != 0) {
+ printf("HackRF: hackrf_set_lna_gain failed with code %d", status);
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ return false;
+ }
+
+ status = hackrf_set_vga_gain(HackRF.device, HackRF.vga_gain);
+ if (status != 0) {
+ printf("HackRF: hackrf_set_vga_gain failed with code %d", 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) {
+ printf("HackRF: can't initialize sample converter\n");
+ return false;
+ }
+
+ return true;
+}
+
+struct timespec thread_cpu;
+
+int handle_hackrf_samples(hackrf_transfer *transfer)
+{
+ struct mag_buf *outbuf;
+ struct mag_buf *lastbuf;
+ unsigned char *buf;
+ int32_t len;
+ uint32_t slen;
+ unsigned next_free_buffer;
+ unsigned free_bufs;
+ unsigned block_duration;
+
+ static int dropping = 0;
+ static uint64_t sampleCounter = 0;
+
+ // Lock the data buffer variables before accessing them
+ pthread_mutex_lock(&Modes.data_mutex);
+ if (Modes.exit) {
+ pthread_mutex_unlock(&Modes.data_mutex);
+ return -1;
+ }
+
+ next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS;
+ outbuf = &Modes.mag_buffers[Modes.first_free_buffer];
+ lastbuf = &Modes.mag_buffers[(Modes.first_free_buffer + MODES_MAG_BUFFERS - 1) % MODES_MAG_BUFFERS];
+ free_bufs = (Modes.first_filled_buffer - next_free_buffer + MODES_MAG_BUFFERS) % MODES_MAG_BUFFERS;
+
+ buf = transfer->buffer;
+ len = transfer->buffer_length;
+
+ // Values returned by HackRF need conversion from signed to unsigned
+ for (int32_t i = 0; i < len; i++) {
+ buf[i] ^= (uint8_t)0x80;
+ }
+
+ slen = len/2; // Drops any trailing odd sample, that's OK
+
+ if (free_bufs == 0 || (dropping && free_bufs < MODES_MAG_BUFFERS/2)) {
+ // FIFO is full. Drop this block.
+ dropping = 1;
+ outbuf->dropped += slen;
+ sampleCounter += slen;
+ pthread_mutex_unlock(&Modes.data_mutex);
+ return -1;
+ }
+
+ dropping = 0;
+ pthread_mutex_unlock(&Modes.data_mutex);
+
+ // Compute the sample timestamp and system timestamp for the start of the block
+ outbuf->sampleTimestamp = sampleCounter * 12e6 / Modes.sample_rate;
+ sampleCounter += slen;
+
+ // Get the approx system time for the start of this block
+ block_duration = 1e3 * slen / Modes.sample_rate;
+ outbuf->sysTimestamp = mstime() - block_duration;
+
+ // Copy trailing data from last block (or reset if not valid)
+ if (outbuf->dropped == 0) {
+ memcpy(outbuf->data, lastbuf->data + lastbuf->length, Modes.trailing_samples * sizeof(uint16_t));
+ } else {
+ memset(outbuf->data, 0, Modes.trailing_samples * sizeof(uint16_t));
+ }
+
+ // Convert the new data
+ outbuf->length = slen;
+ HackRF.converter(buf, &outbuf->data[Modes.trailing_samples], slen, HackRF.converter_state, &outbuf->mean_level, &outbuf->mean_power);
+
+ // Push the new data to the demodulation thread
+ pthread_mutex_lock(&Modes.data_mutex);
+
+ Modes.mag_buffers[next_free_buffer].dropped = 0;
+ Modes.mag_buffers[next_free_buffer].length = 0; // just in case
+ Modes.first_free_buffer = next_free_buffer;
+
+ // accumulate CPU while holding the mutex, and restart measurement
+ end_cpu_timing(&thread_cpu, &Modes.reader_cpu_accumulator);
+ start_cpu_timing(&thread_cpu);
+
+ pthread_cond_signal(&Modes.data_cond);
+ pthread_mutex_unlock(&Modes.data_mutex);
+
+ return 0;
+}
+
+
+void hackRFRun()
+{
+ if (!HackRF.device) {
+ printf("hackRFRun: HackRF.device = NULL\n");
+ return;
+ }
+
+ start_cpu_timing(&thread_cpu);
+
+ int status = hackrf_start_rx(HackRF.device, &handle_hackrf_samples, NULL);
+
+ if (status != 0) {
+ printf("hackrf_start_rx failed");
+ 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) {
+ usleep(10000);
+ }
+
+ printf("HackRF stopped streaming %d\n", hackrf_is_streaming(HackRF.device));
+}
+
+void hackRFClose()
+{
+ if (HackRF.device) {
+ hackrf_close(HackRF.device);
+ hackrf_exit();
+ HackRF.device = NULL;
+ }
+}
diff --git a/sdr_hackrf.h b/sdr_hackrf.h
new file mode 100644
index 0000000..df77634
--- /dev/null
+++ b/sdr_hackrf.h
@@ -0,0 +1,30 @@
+// 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 .
+
+#ifndef HACKRF_H
+#define HACKRF_H
+
+void hackRFInitConfig();
+void hackRFShowHelp();
+bool hackRFHandleOption(int argc, char **argv, int *jptr);
+bool hackRFOpen();
+void hackRFRun();
+void hackRFClose();
+
+#endif