dump1090-fa/sdr_hackrf.c

311 lines
9.0 KiB
C
Raw Permalink Normal View History

2019-12-09 21:55:40 +00:00
// 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 enable_ant_pwr;
2019-12-09 21:55:40 +00:00
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.enable_ant_pwr = 0;
2019-12-09 21:55:40 +00:00
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) {
fprintf(stderr, "Error: --lna-gain must be multiple of 8\n");
2019-12-09 21:55:40 +00:00
return false;
}
if (HackRF.lna_gain > 40 || HackRF.lna_gain < 0) {
fprintf(stderr, "Error: --lna-gain range is 0 - 42\n");
2019-12-09 21:55:40 +00:00
return false;
}
} else if (!strcmp(argv[j], "--vga-gain") && more) {
HackRF.vga_gain = atoi(argv[++j]);
if (HackRF.vga_gain % 2 != 0) {
fprintf(stderr, "Error: --vga-gain must be multiple of 2\n");
2019-12-09 21:55:40 +00:00
return false;
}
if (HackRF.vga_gain > 62 || HackRF.vga_gain < 0) {
fprintf(stderr, "Error: --vga-gain range is 0 - 62\n");
2019-12-09 21:55:40 +00:00
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")) {
2019-12-09 21:55:40 +00:00
HackRF.enable_amp = 1;
} else if (!strcmp(argv[j], "--enable-antenna-power")) {
HackRF.enable_ant_pwr = 1;
}
else {
2019-12-09 21:55:40 +00:00
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("--enable-antenna-power enable DC power to the antenna connector\n");
2019-12-09 21:55:40 +00:00
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()
{
fprintf(stderr, "freq : %" PRIu64 "\n", HackRF.freq);
fprintf(stderr, "lna_gain : %d\n", HackRF.lna_gain);
fprintf(stderr, "vga_gain : %d\n", HackRF.vga_gain);
fprintf(stderr, "samplerate : %d\n", HackRF.rate);
fprintf(stderr, "ppm : %d\n", HackRF.ppm);
2019-12-09 21:55:40 +00:00
}
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) {
fprintf(stderr, "HackRF: hackrf_init failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
return false;
}
status = hackrf_open(&HackRF.device);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_open failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
hackrf_exit();
return false;
}
status = hackrf_set_freq(HackRF.device, HackRF.freq);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_set_freq failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
hackrf_close(HackRF.device);
hackrf_exit();
return false;
}
status = hackrf_set_sample_rate(HackRF.device, HackRF.rate);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_set_sample_rate failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
hackrf_close(HackRF.device);
hackrf_exit();
return false;
}
status = hackrf_set_amp_enable(HackRF.device, HackRF.enable_amp);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_set_amp_enable failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
hackrf_close(HackRF.device);
hackrf_exit();
return false;
}
status = hackrf_set_lna_gain(HackRF.device, HackRF.lna_gain);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_set_lna_gain failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
hackrf_close(HackRF.device);
hackrf_exit();
return false;
}
status = hackrf_set_vga_gain(HackRF.device, HackRF.vga_gain);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_set_vga_gain failed with code %d\n", status);
2019-12-09 21:55:40 +00:00
hackrf_close(HackRF.device);
hackrf_exit();
return false;
}
status = hackrf_set_antenna_enable(HackRF.device, HackRF.enable_ant_pwr);
if (status != 0) {
fprintf(stderr, "HackRF: hackrf_set_antenna_enable failed with code %d\n", status);
hackrf_close(HackRF.device);
hackrf_exit();
return false;
}
2019-12-09 21:55:40 +00:00
show_config();
HackRF.converter = init_converter(INPUT_UC8,
Modes.sample_rate,
Modes.dc_filter,
&HackRF.converter_state);
if (!HackRF.converter) {
fprintf(stderr, "HackRF: can't initialize sample converter\n");
2019-12-09 21:55:40 +00:00
return false;
}
return true;
}
static int handle_hackrf_samples(hackrf_transfer *transfer)
2019-12-09 21:55:40 +00:00
{
static unsigned dropped = 0;
2019-12-09 21:55:40 +00:00
static uint64_t sampleCounter = 0;
2020-08-05 04:00:50 +00:00
sdrMonitor();
if (Modes.exit || transfer->valid_length < 0)
2019-12-09 21:55:40 +00:00
return -1;
uint8_t *buf = transfer->buffer;
unsigned len = transfer->valid_length;
2019-12-09 21:55:40 +00:00
// Values returned by HackRF need conversion from signed to unsigned
for (unsigned i = 0; i < len; i++) {
2019-12-09 21:55:40 +00:00
buf[i] ^= (uint8_t)0x80;
}
unsigned samples_read = len / 2; // Drops any trailing odd sample, that's OK
2019-12-09 21:55:40 +00:00
struct mag_buf *outbuf = fifo_acquire(0 /* don't wait */);
if (!outbuf) {
2019-12-09 21:55:40 +00:00
// FIFO is full. Drop this block.
dropped += samples_read;
sampleCounter += samples_read;
return 0;
}
outbuf->flags = 0;
if (dropped) {
// We previously dropped some samples due to no buffers being available
outbuf->flags |= MAGBUF_DISCONTINUOUS;
outbuf->dropped = dropped;
2019-12-09 21:55:40 +00:00
}
dropped = 0;
2019-12-09 21:55:40 +00:00
// Compute the sample timestamp and system timestamp for the start of the block
outbuf->sampleTimestamp = sampleCounter * 12e6 / Modes.sample_rate;
sampleCounter += samples_read;
2019-12-09 21:55:40 +00:00
// Get the approx system time for the start of this block
uint64_t block_duration = 1e3 * samples_read / Modes.sample_rate;
2019-12-09 21:55:40 +00:00
outbuf->sysTimestamp = mstime() - block_duration;
// Convert the new data
unsigned to_convert = samples_read;
if (to_convert + outbuf->overlap > outbuf->totalLength) {
// how did that happen?
to_convert = outbuf->totalLength - outbuf->overlap;
dropped = samples_read - to_convert;
}
2019-12-09 21:55:40 +00:00
HackRF.converter(buf, &outbuf->data[outbuf->overlap], to_convert, HackRF.converter_state, &outbuf->mean_level, &outbuf->mean_power);
outbuf->validLength = outbuf->overlap + to_convert;
2019-12-09 21:55:40 +00:00
// Push to the demodulation thread
fifo_enqueue(outbuf);
2019-12-09 21:55:40 +00:00
return 0;
}
void hackRFRun()
{
if (!HackRF.device) {
fprintf(stderr, "hackRFRun: HackRF.device = NULL\n");
2019-12-09 21:55:40 +00:00
return;
}
int status = hackrf_start_rx(HackRF.device, &handle_hackrf_samples, NULL);
if (status != 0) {
2020-08-05 04:07:07 +00:00
fprintf(stderr, "hackrf_start_rx failed\n");
2019-12-09 21:55:40 +00:00
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) {
struct timespec slp = { 0, 100 * 1000 * 1000};
nanosleep(&slp, NULL);
2019-12-09 21:55:40 +00:00
}
fprintf(stderr, "HackRF stopped streaming %d\n", hackrf_is_streaming(HackRF.device));
2019-12-09 21:55:40 +00:00
}
void hackRFClose()
{
if (HackRF.device) {
hackrf_close(HackRF.device);
hackrf_exit();
HackRF.device = NULL;
}
}