Compare commits
2 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e2494c2159 | |
|
|
8001832de2 |
4
Makefile
4
Makefile
|
|
@ -35,6 +35,10 @@ ifeq ($(BLADERF), yes)
|
||||||
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
|
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
SDR_OBJ += sdr_soapy.o
|
||||||
|
CFLAGS += $(shell pkg-config --cflags SoapySDR)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs SoapySDR)
|
||||||
|
|
||||||
all: dump1090 view1090
|
all: dump1090 view1090
|
||||||
|
|
||||||
%.o: %.c *.h
|
%.o: %.c *.h
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ typedef enum {
|
||||||
//======================== structure declarations =========================
|
//======================== structure declarations =========================
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF
|
SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_SOAPY
|
||||||
} sdr_type_t;
|
} sdr_type_t;
|
||||||
|
|
||||||
// Structure representing one magnitude buffer
|
// Structure representing one magnitude buffer
|
||||||
|
|
|
||||||
3
sdr.c
3
sdr.c
|
|
@ -28,6 +28,8 @@
|
||||||
# include "sdr_bladerf.h"
|
# include "sdr_bladerf.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "sdr_soapy.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
sdr_type_t sdr_type;
|
sdr_type_t sdr_type;
|
||||||
|
|
@ -85,6 +87,7 @@ static sdr_handler sdr_handlers[] = {
|
||||||
{ "bladerf", SDR_BLADERF, bladeRFInitConfig, bladeRFShowHelp, bladeRFHandleOption, bladeRFOpen, bladeRFRun, bladeRFClose },
|
{ "bladerf", SDR_BLADERF, bladeRFInitConfig, bladeRFShowHelp, bladeRFHandleOption, bladeRFOpen, bladeRFRun, bladeRFClose },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{ "soapy", SDR_SOAPY, soapyInitConfig, soapyShowHelp, soapyHandleOption, soapyOpen, soapyRun, soapyClose },
|
||||||
{ "ifile", SDR_IFILE, ifileInitConfig, ifileShowHelp, ifileHandleOption, ifileOpen, ifileRun, ifileClose },
|
{ "ifile", SDR_IFILE, ifileInitConfig, ifileShowHelp, ifileHandleOption, ifileOpen, ifileRun, ifileClose },
|
||||||
{ "none", SDR_NONE, noInitConfig, noShowHelp, noHandleOption, noOpen, noRun, noClose },
|
{ "none", SDR_NONE, noInitConfig, noShowHelp, noHandleOption, noOpen, noRun, noClose },
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// sdr_soapy.c: SoapySDR support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014-2017 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
// 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_soapy.h"
|
||||||
|
|
||||||
|
#include <SoapySDR/Device.h>
|
||||||
|
#include <SoapySDR/Formats.h>
|
||||||
|
static struct {
|
||||||
|
SoapySDRDevice *dev;
|
||||||
|
SoapySDRStream *stream;
|
||||||
|
|
||||||
|
iq_convert_fn converter;
|
||||||
|
struct converter_state *converter_state;
|
||||||
|
} SOAPY;
|
||||||
|
|
||||||
|
//
|
||||||
|
// =============================== SoapySDR handling ==========================
|
||||||
|
//
|
||||||
|
|
||||||
|
void soapyInitConfig()
|
||||||
|
{
|
||||||
|
SOAPY.dev = NULL;
|
||||||
|
SOAPY.stream = NULL;
|
||||||
|
SOAPY.converter = NULL;
|
||||||
|
SOAPY.converter_state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void soapyShowHelp()
|
||||||
|
{
|
||||||
|
printf(" SoapySDR-specific options (use with --device-type soapy)\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("--device <string> select/configure device\n");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool soapyHandleOption(int argc, char **argv, int *jptr)
|
||||||
|
{
|
||||||
|
MODES_NOTUSED(argc);
|
||||||
|
MODES_NOTUSED(argv);
|
||||||
|
MODES_NOTUSED(jptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool soapyOpen(void)
|
||||||
|
{
|
||||||
|
size_t length;
|
||||||
|
SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length);
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
printf("Found device #%d: ", (int)i);
|
||||||
|
for (size_t j = 0; j < results[i].size; j++)
|
||||||
|
{
|
||||||
|
printf("%s=%s, ", results[i].keys[j], results[i].vals[j]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
SoapySDRKwargsList_clear(results, length);
|
||||||
|
|
||||||
|
SOAPY.dev = SoapySDRDevice_makeStrArgs(Modes.dev_name);
|
||||||
|
if (!SOAPY.dev) {
|
||||||
|
fprintf(stderr, "soapy: failed to create device: %s\n", SoapySDRDevice_lastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoapySDRKwargs result = SoapySDRDevice_getHardwareInfo(SOAPY.dev);
|
||||||
|
for (size_t i = 0; i < result.size; ++i) {
|
||||||
|
printf("%s=%s\n", result.keys[i], result.vals[i]);
|
||||||
|
}
|
||||||
|
SoapySDRKwargs_clear(&result);
|
||||||
|
|
||||||
|
if (SoapySDRDevice_setSampleRate(SOAPY.dev, SOAPY_SDR_RX, 0, Modes.sample_rate) != 0) {
|
||||||
|
fprintf(stderr, "soapy: setSampleRate failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SoapySDRDevice_setFrequency(SOAPY.dev, SOAPY_SDR_RX, 0, Modes.freq, NULL) != 0) {
|
||||||
|
fprintf(stderr, "soapy: setFrequency failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SoapySDRDevice_setGain(SOAPY.dev, SOAPY_SDR_RX, 0, Modes.gain / 10.0) != 0) {
|
||||||
|
fprintf(stderr, "soapy: setGain failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SoapySDRDevice_setBandwidth(SOAPY.dev, SOAPY_SDR_RX, 0, 3.0e6) != 0) {
|
||||||
|
fprintf(stderr, "soapy: setBandwidth failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SoapySDRDevice_setAntenna(SOAPY.dev, SOAPY_SDR_RX, 0, "LNAW") != 0) {
|
||||||
|
fprintf(stderr, "soapy: setAntenna failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "soapy: frequency is %.1f MHz\n",
|
||||||
|
SoapySDRDevice_getFrequency(SOAPY.dev, SOAPY_SDR_RX, 0) / 1e6);
|
||||||
|
fprintf(stderr, "soapy: sample rate is %.1f MHz\n",
|
||||||
|
SoapySDRDevice_getSampleRate(SOAPY.dev, SOAPY_SDR_RX, 0) / 1e6);
|
||||||
|
fprintf(stderr, "soapy: bandwidth is %.1f MHz\n",
|
||||||
|
SoapySDRDevice_getBandwidth(SOAPY.dev, SOAPY_SDR_RX, 0) / 1e6);
|
||||||
|
fprintf(stderr, "soapy: gain mode is %d\n",
|
||||||
|
SoapySDRDevice_getGainMode(SOAPY.dev, SOAPY_SDR_RX, 0));
|
||||||
|
fprintf(stderr, "soapy: gain is %.1f dB\n",
|
||||||
|
SoapySDRDevice_getGain(SOAPY.dev, SOAPY_SDR_RX, 0));
|
||||||
|
fprintf(stderr, "soapy: antenna is %s\n",
|
||||||
|
SoapySDRDevice_getAntenna(SOAPY.dev, SOAPY_SDR_RX, 0));
|
||||||
|
|
||||||
|
size_t channels[1] = { 0 };
|
||||||
|
if (SoapySDRDevice_setupStream(SOAPY.dev, &SOAPY.stream, SOAPY_SDR_RX, SOAPY_SDR_CS16, channels, 1, NULL) != 0) {
|
||||||
|
fprintf(stderr, "soapy: setupStream failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SOAPY.converter = init_converter(INPUT_SC16,
|
||||||
|
Modes.sample_rate,
|
||||||
|
Modes.dc_filter,
|
||||||
|
&SOAPY.converter_state);
|
||||||
|
if (!SOAPY.converter) {
|
||||||
|
fprintf(stderr, "soapy: can't initialize sample converter\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (SOAPY.dev != NULL) {
|
||||||
|
SoapySDRDevice_unmake(SOAPY.dev);
|
||||||
|
SOAPY.dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void soapyRun()
|
||||||
|
{
|
||||||
|
if (!SOAPY.dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SoapySDRDevice_activateStream(SOAPY.dev, SOAPY.stream, 0, 0, 0) != 0) {
|
||||||
|
fprintf(stderr, "soapy: activateStream failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *buffers[1];
|
||||||
|
const int buffer_elements = 131072;
|
||||||
|
buffers[0] = malloc(buffer_elements * 4);
|
||||||
|
|
||||||
|
while (!Modes.exit) {
|
||||||
|
int flags;
|
||||||
|
long long timeNs;
|
||||||
|
int sample_count = SoapySDRDevice_readStream(SOAPY.dev, SOAPY.stream, buffers, buffer_elements, &flags, &timeNs, 5000000);
|
||||||
|
if (sample_count <= 0) {
|
||||||
|
fprintf(stderr, "soapy: readStream failed: %s\n", SoapySDRDevice_lastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Modes.data_mutex);
|
||||||
|
unsigned next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS;
|
||||||
|
if (next_free_buffer == Modes.first_filled_buffer) {
|
||||||
|
// drop it
|
||||||
|
fprintf(stderr, "fifo full\n");
|
||||||
|
pthread_mutex_unlock(&Modes.data_mutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mag_buf *outbuf = &Modes.mag_buffers[Modes.first_free_buffer];
|
||||||
|
struct mag_buf *lastbuf = &Modes.mag_buffers[(Modes.first_free_buffer + MODES_MAG_BUFFERS - 1) % MODES_MAG_BUFFERS];
|
||||||
|
pthread_mutex_unlock(&Modes.data_mutex);
|
||||||
|
|
||||||
|
// Copy trailing data from last block
|
||||||
|
memcpy(outbuf->data, lastbuf->data + lastbuf->length, Modes.trailing_samples * sizeof(uint16_t));
|
||||||
|
SOAPY.converter(buffers[0], &outbuf->data[Modes.trailing_samples], sample_count,
|
||||||
|
SOAPY.converter_state, &outbuf->mean_level, &outbuf->mean_power);
|
||||||
|
outbuf->dropped = 0;
|
||||||
|
outbuf->length = sample_count;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Modes.data_mutex);
|
||||||
|
Modes.mag_buffers[next_free_buffer].dropped = 0;
|
||||||
|
Modes.mag_buffers[next_free_buffer].length = 0;
|
||||||
|
Modes.first_free_buffer = next_free_buffer;
|
||||||
|
pthread_cond_signal(&Modes.data_cond);
|
||||||
|
pthread_mutex_unlock(&Modes.data_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void soapyClose()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "close stream\n");
|
||||||
|
if (SOAPY.stream) {
|
||||||
|
SoapySDRDevice_closeStream(SOAPY.dev, SOAPY.stream);
|
||||||
|
SOAPY.stream = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "close device\n");
|
||||||
|
if (SOAPY.dev) {
|
||||||
|
SoapySDRDevice_unmake(SOAPY.dev);
|
||||||
|
SOAPY.dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SOAPY.converter) {
|
||||||
|
cleanup_converter(SOAPY.converter_state);
|
||||||
|
SOAPY.converter = NULL;
|
||||||
|
SOAPY.converter_state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "all done\n");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// sdr_soapy.h: SoapySDR dongle support (header)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
// 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 SDR_SOAPY_H
|
||||||
|
#define SDR_SOAPY_H
|
||||||
|
|
||||||
|
void soapyInitConfig();
|
||||||
|
void soapyShowHelp();
|
||||||
|
bool soapyOpen();
|
||||||
|
void soapyRun();
|
||||||
|
void soapyClose();
|
||||||
|
bool soapyHandleOption(int argc, char **argv, int *jptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue