311 lines
9.0 KiB
C
311 lines
9.0 KiB
C
// 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;
|
|
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;
|
|
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");
|
|
return false;
|
|
}
|
|
|
|
if (HackRF.lna_gain > 40 || HackRF.lna_gain < 0) {
|
|
fprintf(stderr, "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) {
|
|
fprintf(stderr, "Error: --vga-gain must be multiple of 2\n");
|
|
return false;
|
|
}
|
|
|
|
if (HackRF.vga_gain > 62 || HackRF.vga_gain < 0) {
|
|
fprintf(stderr, "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")) {
|
|
HackRF.enable_amp = 1;
|
|
} else if (!strcmp(argv[j], "--enable-antenna-power")) {
|
|
HackRF.enable_ant_pwr = 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("--enable-antenna-power enable DC power to the antenna connector\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()
|
|
{
|
|
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);
|
|
}
|
|
|
|
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);
|
|
return false;
|
|
}
|
|
|
|
status = hackrf_open(&HackRF.device);
|
|
if (status != 0) {
|
|
fprintf(stderr, "HackRF: hackrf_open failed with code %d\n", status);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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;
|
|
}
|
|
|
|
|
|
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");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int handle_hackrf_samples(hackrf_transfer *transfer)
|
|
{
|
|
static unsigned dropped = 0;
|
|
static uint64_t sampleCounter = 0;
|
|
|
|
sdrMonitor();
|
|
|
|
if (Modes.exit || transfer->valid_length < 0)
|
|
return -1;
|
|
|
|
uint8_t *buf = transfer->buffer;
|
|
unsigned len = transfer->valid_length;
|
|
|
|
// Values returned by HackRF need conversion from signed to unsigned
|
|
for (unsigned i = 0; i < len; i++) {
|
|
buf[i] ^= (uint8_t)0x80;
|
|
}
|
|
|
|
unsigned samples_read = len / 2; // Drops any trailing odd sample, that's OK
|
|
|
|
struct mag_buf *outbuf = fifo_acquire(0 /* don't wait */);
|
|
if (!outbuf) {
|
|
// 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;
|
|
}
|
|
|
|
dropped = 0;
|
|
|
|
// Compute the sample timestamp and system timestamp for the start of the block
|
|
outbuf->sampleTimestamp = sampleCounter * 12e6 / Modes.sample_rate;
|
|
sampleCounter += samples_read;
|
|
|
|
// Get the approx system time for the start of this block
|
|
uint64_t block_duration = 1e3 * samples_read / Modes.sample_rate;
|
|
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;
|
|
}
|
|
|
|
HackRF.converter(buf, &outbuf->data[outbuf->overlap], to_convert, HackRF.converter_state, &outbuf->mean_level, &outbuf->mean_power);
|
|
outbuf->validLength = outbuf->overlap + to_convert;
|
|
|
|
// Push to the demodulation thread
|
|
fifo_enqueue(outbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void hackRFRun()
|
|
{
|
|
if (!HackRF.device) {
|
|
fprintf(stderr, "hackRFRun: HackRF.device = NULL\n");
|
|
return;
|
|
}
|
|
|
|
int status = hackrf_start_rx(HackRF.device, &handle_hackrf_samples, NULL);
|
|
|
|
if (status != 0) {
|
|
fprintf(stderr, "hackrf_start_rx failed\n");
|
|
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);
|
|
}
|
|
|
|
fprintf(stderr, "HackRF stopped streaming %d\n", hackrf_is_streaming(HackRF.device));
|
|
}
|
|
|
|
void hackRFClose()
|
|
{
|
|
if (HackRF.device) {
|
|
hackrf_close(HackRF.device);
|
|
hackrf_exit();
|
|
HackRF.device = NULL;
|
|
}
|
|
}
|