Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/tjmullicani/readsb into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
wiedehopf committed Dec 29, 2023
2 parents ee0cdbc + 806a600 commit 117a5bc
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 1 deletion.
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ READSB_VERSION := "$(shell echo -n `cat version`; { git show -s --format=format:

RTLSDR ?= no
BLADERF ?= no
HACKRF ?= no
PLUTOSDR ?= no
AGGRESSIVE ?= no
HAVE_BIASTEE ?= no
Expand Down Expand Up @@ -101,6 +102,12 @@ ifeq ($(BLADERF), yes)
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
endif

ifeq ($(HACKRF), yes)
SDR_OBJ += sdr_hackrf.o
CFLAGS += $(shell pkg-config --cflags libhackrf) -DENABLE_HACKRF
LIBS_SDR += $(shell pkg-config --libs libhackrf)
endif

ifeq ($(PLUTOSDR), yes)
SDR_OBJ += sdr_plutosdr.o
CFLAGS += $(shell pkg-config --cflags libiio libad9361) -DENABLE_PLUTOSDR
Expand Down
7 changes: 7 additions & 0 deletions help.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ static struct argp_option optionsReadsb[] = {
{"bladerf-fpga", OptBladeFpgaDir, "<path>", 0, "Use alternative FPGA bitstream ('' to disable FPGA load)", 4},
{"bladerf-decimation", OptBladeDecim, "<N>", 0, "Assume FPGA decimates by a factor of N", 4},
{"bladerf-bandwidth", OptBladeBw, "<hz>", 0, "Set LPF bandwidth ('bypass' to bypass the LPF)", 4},
#endif
#ifdef ENABLE_HACKRF
{0,0,0,0, "HackRF options:", 3},
{0,0,0, OPTION_DOC, "use with --device-type hackrf", 3},
{"device", OptDevice, "<ident>", 0, "Select device by serial number", 3},
{"hackrf-enable-ampgain", OptHackRfGainEnable, 0, 0, "Enable amp gain (RF stage) (~11 dB) (default: disabled)", 3},
{"hackrf-vgagain", OptHackRfVgaGain, "<db>", 0, "Set gain (baseband stage) (default: 48, valid: 0-62, 2 dB steps)", 3},
#endif
{0,0,0,0, "Modes-S Beast options, use with --device-type modesbeast:", 5},
{"beast-serial", OptBeastSerial, "<path>", 0, "Path to Beast serial device (default /dev/ttyUSB0)", 5},
Expand Down
4 changes: 4 additions & 0 deletions readsb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
case OptBladeDecim:
case OptBladeBw:
#endif
#ifdef ENABLE_HACKRF
case OptHackRfGainEnable:
case OptHackRfVgaGain:
#endif
#ifdef ENABLE_PLUTOSDR
case OptPlutoUri:
case OptPlutoNetwork:
Expand Down
4 changes: 3 additions & 1 deletion readsb.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ static inline void *malloc_or_exit(size_t alignment, size_t size, const char *fi

typedef enum
{
SDR_NONE = 0, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_MICROBLADERF, SDR_MODESBEAST, SDR_PLUTOSDR, SDR_GNS
SDR_NONE = 0, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_MICROBLADERF, SDR_HACKRF, SDR_MODESBEAST, SDR_PLUTOSDR, SDR_GNS
} sdr_type_t;

// Structure representing one magnitude buffer
Expand Down Expand Up @@ -1236,6 +1236,8 @@ enum {
OptBladeFpgaDir,
OptBladeDecim,
OptBladeBw,
OptHackRfGainEnable,
OptHackRfVgaGain,
OptPlutoUri,
OptPlutoNetwork,
};
Expand Down
7 changes: 7 additions & 0 deletions sdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
#include "sdr_bladerf.h"
#include "sdr_ubladerf.h"
#endif
#ifdef ENABLE_HACKRF
#include "sdr_hackrf.h"
#endif
#ifdef ENABLE_PLUTOSDR
#include "sdr_plutosdr.h"
#endif
Expand Down Expand Up @@ -91,6 +94,10 @@ static sdr_handler sdr_handlers[] = {
{ ubladeRFInitConfig, ubladeRFHandleOption, ubladeRFOpen, ubladeRFRun, noCancel, ubladeRFClose, "ubladerf", SDR_MICROBLADERF, 0},
#endif

#ifdef ENABLE_HACKRF
{ hackRFInitConfig, hackRFHandleOption, hackRFOpen, hackRFRun, noCancel, hackRFClose, "hackrf", SDR_HACKRF, 0},
#endif

#ifdef ENABLE_PLUTOSDR
{ plutosdrInitConfig, plutosdrHandleOption, plutosdrOpen, plutosdrRun, noCancel, plutosdrClose, "plutosdr", SDR_PLUTOSDR, 0},
#endif
Expand Down
289 changes: 289 additions & 0 deletions sdr_hackrf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
// Part of readsb, a Mode-S/ADSB/TIS message decoder.
//
// sdr_hackrf.c: HackRF support
//
// Copyright (c) 2023 Timothy Mullican <[email protected]>
//
// This code is based on dump1090_sdrplus.
//
// Copyright (C) 2012 by Salvatore Sanfilippo <[email protected]>
// HackRF One support added by Ilker Temir <[email protected]>
//
// This file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// 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 "readsb.h"

#include <libhackrf/hackrf.h>
#include <inttypes.h>

static struct {
const char *device_str;
unsigned block_size;
hackrf_device *device;
iq_convert_fn converter;
struct converter_state *converter_state;
// HackRF has three gain controls
// RF ("amp", 0 or ~11 dB)
// IF ("lna", 0 to 40 dB in 8 dB steps)
// baseband ("vga", 0 to 62 dB in 2 dB steps)
bool rf_gain;
unsigned vga_gain;
} hackRF;

void hackRFInitConfig() {
hackRF.device_str = NULL;
hackRF.device = NULL;
hackRF.rf_gain = false;
hackRF.vga_gain = 48;
}

bool hackRFHandleOption(int argc, char *argv) {
switch (argc) {
case OptHackRfGainEnable:
hackRF.rf_gain = true;
break;
case OptHackRfVgaGain:
hackRF.vga_gain = atoi(argv);
break;
default:
return false;
}
return true;
}

bool hackRFOpen() {
if (hackRF.device) {
return true;
}

int status;

status = hackrf_init();
if ((status = hackrf_init()) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_init failed: %s\n", hackrf_error_name(status));
goto error;
}

fprintf(stderr, "Opening HackRF: %s\n", Modes.dev_name);
if (Modes.dev_name) {
status = hackrf_open_by_serial(Modes.dev_name, &hackRF.device);
} else {
status = hackrf_open(&hackRF.device);
}
if (status != HACKRF_SUCCESS) {
fprintf(stderr, "Failed to open hackRF: %s\n", hackrf_error_name(status));
goto error;
}

if ((status = hackrf_set_sample_rate(hackRF.device, Modes.sample_rate)) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_set_sample_rate failed: %s\n", hackrf_error_name(status));
goto error;
}

if ((status = hackrf_set_freq(hackRF.device, Modes.freq)) != HACKRF_SUCCESS ) {
fprintf(stderr, "hackrf_set_freq failed: %s\n", hackrf_error_name(status));
goto error;
}

if (Modes.gain == MODES_AUTO_GAIN || Modes.gain >= 400) {
// hackRF doesn't have automatic gain control
Modes.gain = 400;
}
if (Modes.gain < 0) {
// gain is unsigned
Modes.gain = 0;
}

if (hackRF.rf_gain) {
if ((status = hackrf_set_amp_enable(hackRF.device, 1)) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_set_amp_enable failed: %s\n", hackrf_error_name(status));
goto error;
}
}

if ((status = hackrf_set_lna_gain(hackRF.device, Modes.gain / 10)) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_set_lna_gain failed: %s\n", hackrf_error_name(status));
goto error;
}

if ((status = hackrf_set_vga_gain(hackRF.device, hackRF.vga_gain)) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_set_vga_gain failed: %s\n", hackrf_error_name(status));
goto error;
}

if (Modes.biastee) {
fprintf(stderr, "Enabling Bias Tee\n");
if ((status = hackrf_set_antenna_enable(hackRF.device, 1)) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_set_antenna_enable failed: %s\n", hackrf_error_name(status));
}
}

fprintf (stderr, "HackRF successfully initialized "
"(AMP Enable: %i, LNA Gain: %i, VGA Gain: %i).\n",
Modes.biastee, Modes.gain / 10, hackRF.vga_gain);

hackRF.converter = init_converter(INPUT_UC8,
Modes.sample_rate,
Modes.dc_filter,
&hackRF.converter_state);
if (!hackRF.converter) {
fprintf(stderr, "can't initialize sample converter\n");
goto error;
}

return true;

error:
if (hackRF.device) {
hackrf_close(hackRF.device);
hackrf_exit();
hackRF.device = NULL;
}
return false;
}

static struct timespec thread_cpu;

static int hackrfCallback(hackrf_transfer *transfer) {
struct mag_buf *outbuf;
struct mag_buf *lastbuf;
uint32_t slen;
unsigned next_free_buffer;
unsigned free_bufs;
int64_t block_duration;

static int was_odd = 0;
static int dropping = 0;
static uint64_t sampleCounter = 0;

uint8_t *buf = transfer->buffer;
uint32_t len = transfer->buffer_length;

// Lock the data buffer variables before accessing them
lockReader();

// HackRF one returns signed IQ values, convert them to unsigned
for (uint32_t i = 0; i < len; i++) {
buf[i] ^= 0x80; // Flip the MSB to convert
}

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;

if (len != Modes.sdr_buf_size) {
fprintf(stderr, "weirdness: hackRF gave us a block with an unusual size (got %u bytes, expected %u bytes)\n",
(unsigned) len, (unsigned) Modes.sdr_buf_size);
if (len > Modes.sdr_buf_size) {
unsigned discard = (len - Modes.sdr_buf_size + 1) / 2;
outbuf->dropped += discard;
buf += discard * 2;
len -= discard * 2;
}
}

if (was_odd) {
++buf;
--len;
++outbuf->dropped;
}

was_odd = (len & 1);
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;
// make extra sure that the decode thread isn't sleeping
unlockReader();
return 1;
}

dropping = 0;
unlockReader();

// 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();
outbuf->sysMicroseconds = mono_micro_seconds();

outbuf->sysTimestamp -= block_duration;
outbuf->sysMicroseconds -= block_duration * 1000;

// 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
lockReader();

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);

wakeDecode();
unlockReader();

return 0;
}

void hackRFRun() {
if (!hackRF.device) {
return;
}

start_cpu_timing(&thread_cpu);

int status;
if ((status = hackrf_start_rx(hackRF.device, hackrfCallback, NULL)) != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_start_rx failed: %s\n", hackrf_error_name(status));
}

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
while (!Modes.exit) {
threadTimedWait(&Threads.reader, &ts, 50);
}
}

void hackRFClose() {
hackrf_stop_rx(hackRF.device);

if (hackRF.converter) {
cleanup_converter(&hackRF.converter_state);
hackRF.converter = NULL;
}

if (hackRF.device) {
hackrf_close(hackRF.device);
hackRF.device = NULL;
}
}
Loading

0 comments on commit 117a5bc

Please sign in to comment.