Skip to content

Commit

Permalink
Add UHD driver for Ettus radios.
Browse files Browse the repository at this point in the history
$ ./dump1090 --device-type uhd --gain 30
  • Loading branch information
anarkiwi committed Aug 9, 2023
1 parent e3b3fa8 commit 905a406
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 4 deletions.
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@ ifeq ($(PKGCONFIG), yes)
ifndef LIMESDR
LIMESDR := $(shell pkg-config --exists LimeSuite && echo "yes" || echo "no")
endif

ifndef UHD
UHD := $(shell pkg-config --exists uhd && echo "yes" || echo "no")
endif
else
# pkg-config not available. Only use explicitly enabled libraries.
RTLSDR ?= no
BLADERF ?= no
HACKRF ?= no
LIMESDR ?= no
UHD ?= no
endif

HOST_UNAME := $(shell uname)
Expand Down Expand Up @@ -155,6 +160,12 @@ ifeq ($(LIMESDR), yes)
LIBS_SDR += $(shell pkg-config --libs LimeSuite)
endif

ifeq ($(UHD), yes)
SDR_OBJ += sdr_uhd.o
DUMP1090_CPPFLAGS += -DENABLE_UHD
DUMP1090_CFLAGS += $(shell pkg-config --cflags uhd)
LIBS_SDR += $(shell pkg-config --libs uhd)
endif

##
## starch (runtime DSP code selection) mix, architecture-specific
Expand Down Expand Up @@ -201,6 +212,7 @@ showconfig:
@echo " BladeRF support: $(BLADERF)" >&2
@echo " HackRF support: $(HACKRF)" >&2
@echo " LimeSDR support: $(LIMESDR)" >&2
@echo " UHD support : $(UHD)" >&2

%.o: %.c *.h
$(CC) $(ALL_CCFLAGS) -c $< -o $@
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ many other Linux or Unix-like systems.
## Building under bullseye, buster, or stretch

```bash
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev libuhd-dev
$ ./prepare-build.sh bullseye # or buster, or stretch
$ cd package-bullseye # or buster, or stretch
$ dpkg-buildpackage -b --no-sign
Expand All @@ -35,7 +35,7 @@ limited SDR support only.

Pass `--build-profiles` to `dpkg-buildpackage` with a comma-separated list of
profiles. The list of profiles should include `custom` and zero or more of
`rtlsdr`, `bladerf`, `hackrf`, `limesdr` depending on what you want:
`rtlsdr`, `bladerf`, `hackrf`, `limesdr`, `uhd` depending on what you want:

```bash
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr # builds with rtlsdr support only
Expand All @@ -61,6 +61,10 @@ libhackrf.
``make LIMESDR=no`` will disable LimeSDR support and remove the dependency on
libLimeSuite.

``make UHD=no`` will disable UHD support and remove the dependency on
uhd-dev.


## Building on OSX

Minimal testing on Mojave 10.14.6, YMMV.
Expand Down
2 changes: 1 addition & 1 deletion dump1090.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ typedef enum {
//======================== structure declarations =========================

typedef enum {
SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_HACKRF, SDR_LIMESDR
SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_HACKRF, SDR_LIMESDR, SDR_UHD
} sdr_type_t;

// Program global state
Expand Down
7 changes: 6 additions & 1 deletion sdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
#ifdef ENABLE_LIMESDR
# include "sdr_limesdr.h"
#endif
#ifdef ENABLE_UHD
# include "sdr_uhd.h"
#endif

typedef struct {
const char *name;
Expand Down Expand Up @@ -128,7 +131,9 @@ static sdr_handler sdr_handlers[] = {
#ifdef ENABLE_LIMESDR
{ "limesdr", SDR_LIMESDR, limesdrInitConfig, limesdrShowHelp, limesdrHandleOption, limesdrOpen, limesdrRun, noStop, limesdrClose, noGetGain, noGetMaxGain, noGetGainDb, noSetGain },
#endif

#ifdef ENABLE_UHD
{ "uhd", SDR_UHD, uhdInitConfig, uhdShowHelp, uhdHandleOption, uhdOpen, uhdRun, noStop, uhdClose, noGetGain, noGetMaxGain, noGetGainDb, noSetGain },
#endif
{ "none", SDR_NONE, noInitConfig, noShowHelp, noHandleOption, noOpen, noRun, noStop, noClose, noGetGain, noGetMaxGain, noGetGainDb, noSetGain },
{ "ifile", SDR_IFILE, ifileInitConfig, ifileShowHelp, ifileHandleOption, ifileOpen, ifileRun, noStop, ifileClose, noGetGain, noGetMaxGain, noGetGainDb, noSetGain },

Expand Down
240 changes: 240 additions & 0 deletions sdr_uhd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// sdr_bladerf.h: UHD support (header)
//
// Copyright (c) 2017 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_uhd.h"

#include <inttypes.h>

// complex int16
#define SAMPLE_SIZE 4

static struct {
uhd_usrp_handle *usrp;
uhd_rx_metadata_handle *md;
uhd_rx_streamer_handle *rx_streamer;
char *device_args;
size_t channel;
char *sample_data;

iq_convert_fn converter;
struct converter_state *converter_state;
} uhd;

void uhdClose() {
if (uhd.rx_streamer) {
uhd_rx_streamer_free(uhd.rx_streamer);
free(uhd.rx_streamer);
uhd.rx_streamer = NULL;
}
if (uhd.md) {
uhd_rx_metadata_free(uhd.md);
free(uhd.md);
uhd.md = NULL;
}
if (uhd.usrp) {
uhd_usrp_free(uhd.usrp);
free(uhd.usrp);
uhd.usrp = NULL;
}
if (uhd.sample_data) {
free(uhd.sample_data);
uhd.sample_data = NULL;
}
if (uhd.device_args) {
free(uhd.device_args);
uhd.device_args = NULL;
}
}

void uhdInitConfig() {
uhd.usrp = NULL;
uhd.md = NULL;
uhd.rx_streamer = NULL;
uhd.device_args = NULL;
uhd.sample_data = NULL;
uhd.channel = 0;
}

void uhdShowHelp() {
printf(" uhd-specific options (use with --device-type uhd)\n");
printf("\n");
printf("--device-args <args> UHD device args\n");
printf("\n");
}

bool uhdHandleOption(int argc, char **argv, int *jptr) {
int j = *jptr;
bool more = (j+1 < argc);
if (!strcmp(argv[j], "--uhd-device-args") && more) {
uhd.device_args = strdup(argv[++j]);
} else {
return false;
}

*jptr = j;
return true;
}

bool uhdOpen() {
uhd_tune_request_t tune_request = {
.target_freq = Modes.freq,
.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO,
};
uhd_tune_result_t tune_result;

if (!uhd.device_args) {
uhd.device_args = strdup("");
}

int uhd_error;

uhd.usrp = malloc(sizeof(uhd_usrp_handle));
uhd_error = uhd_usrp_make(uhd.usrp, uhd.device_args);
if (uhd_error) {
fprintf(stderr, "uhd_usrp_make() failed: %x", uhd_error);
goto failed;
}

uhd.md = malloc(sizeof(uhd_rx_metadata_handle));
uhd_error = uhd_rx_metadata_make(uhd.md);
if (uhd_error) {
fprintf(stderr, "uhd_rx_metadata_make() failed: %x", uhd_error);
goto failed;
}

uhd.rx_streamer = malloc(sizeof(uhd_rx_streamer_handle));
uhd_error = uhd_rx_streamer_make(uhd.rx_streamer);
if (uhd_error) {
fprintf(stderr, "uhd_rx_streamer_make() failed: %x", uhd_error);
goto failed;
}

fprintf(stderr, "setting bw, rx rate to %fMsps\n", Modes.sample_rate / 1e6);
uhd_error = uhd_usrp_set_rx_rate(*uhd.usrp, Modes.sample_rate, uhd.channel);
if (uhd_error) {
fprintf(stderr, "uhd_usrp_set_rx_rate() failed: %x", uhd_error);
goto failed;
}

uhd_error = uhd_usrp_set_rx_bandwidth(*uhd.usrp, Modes.sample_rate, uhd.channel);
if (uhd_error) {
fprintf(stderr, "uhd_usrp_set_rx_bandwidth() failed: %x", uhd_error);
goto failed;
}

if (Modes.gain != MODES_DEFAULT_GAIN) {
fprintf(stderr, "setting rx gain to %f\n", Modes.gain);
uhd_error = uhd_usrp_set_rx_gain(*uhd.usrp, Modes.gain, uhd.channel, "");
if (!uhd_error) {
fprintf(stderr, "uhd_usrp_set_rx_gain() failed: %x", uhd_error);
goto failed;
}
}

fprintf(stderr, "setting rx freq to %fMHz\n", Modes.freq / 1e6);
uhd_error = uhd_usrp_set_rx_freq(*uhd.usrp, &tune_request, uhd.channel, &tune_result);
if (uhd_error) {
fprintf(stderr, "uhd_usrp_set_rx_freq() failed: %x", uhd_error);
goto failed;
}

uhd.converter = init_converter(
INPUT_SC16Q11, Modes.sample_rate, Modes.dc_filter, &uhd.converter_state);

return true;

failed:
uhdClose();
return false;
}

void uhdRun() {
uhd_stream_args_t stream_args = {
.cpu_format = "sc16",
.otw_format = "sc16",
.args = "",
.channel_list = &uhd.channel,
.n_channels = 1
};

uhd_stream_cmd_t stream_cmd = {
.stream_mode = UHD_STREAM_MODE_START_CONTINUOUS,
.stream_now = true
};

uhd_stream_cmd_t stop_stream_cmd = {
.stream_mode = UHD_STREAM_MODE_STOP_CONTINUOUS,
};

size_t num_rx_samps = 0;
struct mag_buf *outbuf = NULL;
int uhd_error;

uhd_error = uhd_usrp_get_rx_stream(*uhd.usrp, &stream_args, *uhd.rx_streamer);
if (uhd_error) {
fprintf(stderr, "uhd_usrp_get_rx_stream() failed: %x\n", uhd_error);
return;
}

fprintf(stderr, "streaming...\n");
uhd.sample_data = malloc(MODES_MAG_BUF_SAMPLES * SAMPLE_SIZE);
int64_t full_secs;
double frac_secs;
uhd_rx_metadata_time_spec(*uhd.md, &full_secs, &frac_secs);
double first_recv_time = full_secs + frac_secs;

uhd_error = uhd_rx_streamer_issue_stream_cmd(*uhd.rx_streamer, &stream_cmd);
if (uhd_error) {
fprintf(stderr, "uhd_rx_streamer_issue_stream_cmd() failed: %x\n", uhd_error);
return;
}

for (;;) {
outbuf = fifo_acquire(0);
if (!outbuf) {
if (Modes.exit) {
break;
}
fprintf(stderr, "could not get outbuf\n");
continue;
}

outbuf->sysTimestamp = mstime();
uhd_rx_streamer_recv(*uhd.rx_streamer, (void **) &uhd.sample_data, MODES_MAG_BUF_SAMPLES, uhd.md, 3.0, false, &num_rx_samps);
uhd_rx_metadata_error_code_t error_code;
uhd_rx_metadata_error_code(*uhd.md, &error_code);
if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE) {
fprintf(stderr, "error code while streaming: %x\n", error_code);
break;
}
uhd_rx_metadata_time_spec(*uhd.md, &full_secs, &frac_secs);
double recv_time = full_secs + frac_secs;
outbuf->sampleTimestamp = (recv_time - first_recv_time) * 12e6 / Modes.sample_rate;

uhd.converter(uhd.sample_data, &outbuf->data[outbuf->overlap], num_rx_samps, uhd.converter_state, &outbuf->mean_level, &outbuf->mean_power);
outbuf->validLength = outbuf->overlap + num_rx_samps;
outbuf->flags = 0;

fifo_enqueue(outbuf);
}

uhd_rx_streamer_issue_stream_cmd(*uhd.rx_streamer, &stop_stream_cmd);
}
34 changes: 34 additions & 0 deletions sdr_uhd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// sdr_bladerf.h: UHD support (header)
//
// Copyright (c) 2017 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 UHD_H
#define UHD_H

#include <uhd.h>

// Support for UHD SDR

void uhdInitConfig();
void uhdShowHelp();
bool uhdHandleOption(int argc, char **argv, int *jptr);
bool uhdOpen();
void uhdRun();
void uhdClose();

#endif

0 comments on commit 905a406

Please sign in to comment.