Added support for HackRF One

This commit is contained in:
Carlos Pizarro 2019-12-09 18:55:40 -03:00
parent 089684e20f
commit 0f0696c97b
No known key found for this signature in database
GPG Key ID: DDA8A83567C1D234
7 changed files with 379 additions and 2 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

7
sdr.c
View File

@ -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 },

322
sdr_hackrf.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#include "dump1090.h"
#include "sdr_hackrf.h"
#include <libhackrf/hackrf.h>
#include <inttypes.h>
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;
}
}

30
sdr_hackrf.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#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