Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UHD driver for Ettus radios. #223

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ ifeq ($(PKGCONFIG), yes)
LIMESDR := $(shell pkg-config --exists LimeSuite && echo "yes" || echo "no")
endif

ifndef UHD
UHD := $(shell pkg-config --exists uhd && echo "yes" || echo "no")
endif

ifndef SOAPYSDR
SOAPYSDR := $(shell pkg-config --exists SoapySDR && echo "yes" || echo "no")
endif
Expand All @@ -41,6 +45,7 @@ else
BLADERF ?= no
HACKRF ?= no
LIMESDR ?= no
UHD ?= no
SOAPYSDR ?= no
endif

Expand Down Expand Up @@ -160,14 +165,20 @@ 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

ifeq ($(SOAPYSDR), yes)
SDR_OBJ += sdr_soapy.o
DUMP1090_CPPFLAGS += -DENABLE_SOAPYSDR
DUMP1090_CFLAGS += $(shell pkg-config --cflags SoapySDR)
LIBS_SDR += $(shell pkg-config --libs SoapySDR)
endif


##
## starch (runtime DSP code selection) mix, architecture-specific
##
Expand Down Expand Up @@ -210,13 +221,14 @@ include dsp/generated/makefile.$(STARCH_MIX)

showconfig:
@echo "Building with:" >&2
@echo " Version string: $(DUMP1090_VERSION)" >&2
@echo " Architecture: $(ARCH)" >&2
@echo " DSP mix: $(STARCH_MIX)" >&2
@echo " RTLSDR support: $(RTLSDR)" >&2
@echo " BladeRF support: $(BLADERF)" >&2
@echo " HackRF support: $(HACKRF)" >&2
@echo " LimeSDR support: $(LIMESDR)" >&2
@echo " Version string: $(DUMP1090_VERSION)" >&2
@echo " Architecture: $(ARCH)" >&2
@echo " DSP mix: $(STARCH_MIX)" >&2
@echo " RTLSDR support: $(RTLSDR)" >&2
@echo " BladeRF support: $(BLADERF)" >&2
@echo " HackRF support: $(HACKRF)" >&2
@echo " LimeSDR support: $(LIMESDR)" >&2
@echo " UHD support : $(UHD)" >&2
@echo " SoapySDR support: $(SOAPYSDR)" >&2

%.o: %.c *.h
Expand Down
7 changes: 5 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 libsoapysdr-dev
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev libsoapysdr-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`, 'soapysdr' depending on what you want:
`rtlsdr`, `bladerf`, `hackrf`, `limesdr`, 'soapysdr', `uhd` depending on what you want:

```bash
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr # builds with rtlsdr support only
Expand All @@ -62,6 +62,9 @@ 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.

``make SOAPYSDR=no`` will disable SoapySDR support and remove the dependency on
libSoapySDR.

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_SOAPYSDR
SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_HACKRF, SDR_LIMESDR, SDR_SOAPYSDR, SDR_UHD
} sdr_type_t;

// Program global state
Expand Down
6 changes: 6 additions & 0 deletions 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
#ifdef ENABLE_SOAPYSDR
# include "sdr_soapy.h"
#endif
Expand Down Expand Up @@ -131,6 +134,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
#ifdef ENABLE_SOAPYSDR
{ "soapy", SDR_SOAPYSDR, soapyInitConfig, soapyShowHelp, soapyHandleOption, soapyOpen, soapyRun, noStop, soapyClose, soapyGetGain, soapyGetMaxGain, soapyGetGainDb, soapySetGain },
#endif
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