From 53183c0b2a26006e5ac8d97fe6a09d771638f7a7 Mon Sep 17 00:00:00 2001 From: Gluttton Date: Sun, 26 Jul 2020 16:52:48 +0300 Subject: [PATCH 01/10] limesdr: basic implementation of LimeSDR support The commit provides a basic implementation of support for LimeSDR USB receivers based on LMS7002 chip. The solution has several limitations: - passing parameters for tune LimeSDR receiver via command-line options is not implemented; - only hardcoded configuration is used (channel 0 of lower band LNA, LMS_FMT_I16 format, gain, bandwidth and timeout); - only one device is supported and it is not possible to select a desired one in case if several devices are connected to the host. Test: compare the output of the program for RTL and LimeSDR receivers. Environment: - RTL2832SDR dongle; - LMS7002M based USB LimeSDR board; - 800MHz-2200MHz omnidirectional antenna with SMA connector. Procedure: - connect RTL dongle to the host and start the program with the following parameters: $ ./dump1090 --device-type rtlsdr --interactive - wait until several planes will be detected; - stop the program, connect the LimeSDR board to the host and restart the program with the following parameters: $ ./dump1090 --device-type limesdr --interactive - ensure that the same planes are detected. Acceptance criteria: the same planes are detected using both receivers and track information matches with information from the FlightRadar24 application. Signed-off-by: Gluttton --- Makefile | 8 ++ README.md | 12 +- dump1090.c | 3 + dump1090.h | 2 +- sdr.c | 7 + sdr_limesdr.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++ sdr_limesdr.h | 30 +++++ 7 files changed, 404 insertions(+), 3 deletions(-) create mode 100644 sdr_limesdr.c create mode 100644 sdr_limesdr.h diff --git a/Makefile b/Makefile index 6343ffb..9ec046f 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PROGNAME=dump1090 RTLSDR ?= yes BLADERF ?= yes +LIMESDR ?= yes CPPFLAGS += -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\" @@ -39,6 +40,13 @@ ifeq ($(BLADERF), yes) LIBS_SDR += $(shell pkg-config --libs libbladeRF) endif +ifeq ($(LIMESDR), yes) + SDR_OBJ += sdr_limesdr.o + CPPFLAGS += -DENABLE_LIMESDR + CFLAGS += $(shell pkg-config --cflags LimeSuite) + LIBS_SDR += $(shell pkg-config --libs LimeSuite) +endif + all: dump1090 view1090 %.o: %.c *.h diff --git a/README.md b/README.md index 31864c4..392b17b 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,11 @@ see https://flightaware.com/adsb/piaware/install This is packaged with jessie. `sudo apt-get install librtlsdr-dev` +### Dependencies - LimeSDR + +You will need a build of [LimeSuite](https://github.com/myriadrf/LimeSuite). +See detailed instruction on [the official Wiki](https://wiki.myriadrf.org/Lime_Suite) how to build and install it. + ### Actually building it Nothing special, just build it (`dpkg-buildpackage -b`) @@ -45,7 +50,7 @@ Nothing special, just build it (`dpkg-buildpackage -b`) First run `prepare-wheezy-tree.sh`. This will create a package tree in package-wheezy/. Build in there (`dpkg-buildpackage -b`) -The wheezy build does not include bladeRF support. +The wheezy build does not include bladeRF and LimeSDR support. ## Building manually @@ -56,5 +61,8 @@ install them (and a method for starting them) yourself. ``make BLADERF=no`` will disable bladeRF support and remove the dependency on libbladeRF. -``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on +``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on librtlsdr. + +``make LIMESDR=no`` will disable LimeSDR support and remove the dependency on +libLimeSuite. diff --git a/dump1090.c b/dump1090.c index 2506e8c..1274a0f 100644 --- a/dump1090.c +++ b/dump1090.c @@ -267,6 +267,9 @@ void showHelp(void) { #ifdef ENABLE_BLADERF "ENABLE_BLADERF " #endif +#ifdef ENABLE_LIMESDR + "ENABLE_LIMESDR " +#endif #ifdef SC16Q11_TABLE_BITS // This is a little silly, but that's how the preprocessor works.. #define _stringize(x) #x diff --git a/dump1090.h b/dump1090.h index 5c7cf73..645c9c8 100644 --- a/dump1090.h +++ b/dump1090.h @@ -280,7 +280,7 @@ typedef enum { //======================== structure declarations ========================= typedef enum { - SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF + SDR_NONE, SDR_IFILE, SDR_RTLSDR, SDR_BLADERF, SDR_LIMESDR } sdr_type_t; // Structure representing one magnitude buffer diff --git a/sdr.c b/sdr.c index 89fe8f4..84cfff7 100644 --- a/sdr.c +++ b/sdr.c @@ -27,6 +27,9 @@ #ifdef ENABLE_BLADERF # include "sdr_bladerf.h" #endif +#ifdef ENABLE_LIMESDR +# include "sdr_limesdr.h" +#endif typedef struct { const char *name; @@ -85,6 +88,10 @@ static sdr_handler sdr_handlers[] = { { "bladerf", SDR_BLADERF, bladeRFInitConfig, bladeRFShowHelp, bladeRFHandleOption, bladeRFOpen, bladeRFRun, bladeRFClose }, #endif +#ifdef ENABLE_LIMESDR + { "limesdr", SDR_LIMESDR, limesdrInitConfig, limesdrShowHelp, limesdrHandleOption, limesdrOpen, limesdrRun, limesdrClose }, +#endif + { "ifile", SDR_IFILE, ifileInitConfig, ifileShowHelp, ifileHandleOption, ifileOpen, ifileRun, ifileClose }, { "none", SDR_NONE, noInitConfig, noShowHelp, noHandleOption, noOpen, noRun, noClose }, diff --git a/sdr_limesdr.c b/sdr_limesdr.c new file mode 100644 index 0000000..17bb81a --- /dev/null +++ b/sdr_limesdr.c @@ -0,0 +1,345 @@ +// Part of dump1090, a Mode S message decoder for RTLSDR devices. +// +// sdr_limesdr.c: LimeSDR dongle support +// +// Copyright (c) 2020 Gluttton +// +// 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 . + +// This file incorporates work covered by the following copyright and +// permission notice: +// +// Copyright (C) 2012 by Salvatore Sanfilippo +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "dump1090.h" +#include "sdr_limesdr.h" + +#include + +static struct { + lms_device_t *dev; + lms_stream_t stream; + bool is_stream_opened; + bool is_stop; + int bytes_in_sample; + iq_convert_fn converter; + struct converter_state *converter_state; +} LimeSDR; + +void limesdrLogHandler(int lvl, const char *msg) +{ + FILE *out = NULL; + switch (lvl) { + default: + case LMS_LOG_DEBUG: + return; + case LMS_LOG_INFO: + out = stdout; + break; + case LMS_LOG_WARNING: + case LMS_LOG_ERROR: + case LMS_LOG_CRITICAL: + out = stderr; + break; + } + + fprintf(out, "limesdr: %s\n", msg); +} + +void limesdrInitConfig() +{ + LimeSDR.dev = NULL; + LimeSDR.stream.channel = 0; + LimeSDR.stream.fifoSize = 1024 * 1024; + LimeSDR.stream.throughputVsLatency = 1.0; // best throughput + LimeSDR.stream.isTx = false; + LimeSDR.stream.dataFmt = LMS_FMT_I16; // should be matched with conveter + LimeSDR.is_stream_opened = false; + LimeSDR.is_stop = false; + LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 + + LMS_RegisterLogHandler(limesdrLogHandler); +} + +void limesdrShowHelp() +{ + printf(" limesdr-specific options (use with --device-type limesdr)\n"); + printf("\n"); + printf("so far there is no any LimeSDR specific option...\n"); + printf("\n"); +} + +bool limesdrHandleOption(int argc, char **argv, int *jptr) +{ + MODES_NOTUSED(argc); + MODES_NOTUSED(argv); + MODES_NOTUSED(jptr); + + return false; +} + +bool limesdrOpen(void) +{ + const size_t devCountMax = 8; + lms_info_str_t list[devCountMax]; + const int devCount = LMS_GetDeviceList(list); + if (devCount < 0) { + fprintf(stderr, "limesdr: unable to get a number of connected devices\n"); + goto error; + } + + if (devCount < 1) { + fprintf(stderr, "limesdr: no connected devices\n"); + goto error; + } + + if (LMS_Open(&LimeSDR.dev, list[0], NULL) ) { + fprintf(stderr, "limesdr: unable to open device\n"); + goto error; + } + + if (LMS_Init(LimeSDR.dev)) { + fprintf(stderr, "limesdr: unable to initialize device\n"); + goto error; + } + + if (LMS_EnableChannel(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, true)) { + fprintf(stderr, "limesdr: unable to enable RX channel\n"); + goto error; + } + + if (LMS_SetLOFrequency(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.freq)) { + fprintf(stderr, "limesdr: unable to set frequency\n"); + goto error; + } + + if (LMS_SetAntenna(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LMS_PATH_LNAL)) { + fprintf(stderr, "limesdr: unable to set RF port\n"); + goto error; + } + + if (LMS_SetSampleRate(LimeSDR.dev, Modes.sample_rate, 0/*default oversample*/)) { + fprintf(stderr, "limesdr: unable to set sampling rate\n"); + goto error; + } + + if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 0.85)) { + fprintf(stderr, "limesdr: unable to set gain\n"); + goto error; + } + + if (LMS_SetLPFBW(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.sample_rate)) { + fprintf(stderr, "limesdr: unable to set LP filter\n"); + goto error; + } + + LimeSDR.is_stream_opened = true; + if (LMS_SetupStream(LimeSDR.dev, &LimeSDR.stream)) { + fprintf(stderr, "limesdr: unable to setup stream\n"); + LimeSDR.is_stream_opened = false; + goto error; + } + + if (LMS_Calibrate(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 2.5e6/*0.5e5*/, 0)) { + fprintf(stderr, "limesdr: unable to calibrate device\n"); + goto error; + } + + LimeSDR.converter = init_converter(INPUT_SC16, + Modes.sample_rate, + Modes.dc_filter, + &LimeSDR.converter_state); + if (!LimeSDR.converter) { + fprintf(stderr, "limesdr: can't initialize sample converter.\n"); + goto error; + } + + return true; + + error: + if (LimeSDR.is_stream_opened) { + LMS_DestroyStream(LimeSDR.dev, &LimeSDR.stream); + LimeSDR.is_stream_opened = false; + } + + if (LimeSDR.dev) { + LMS_Close(LimeSDR.dev); + LimeSDR.dev = NULL; + } + + return false; +} + +static struct timespec limesdr_thread_cpu; + +void limesdrCallback(unsigned char *buf, uint32_t len, void *ctx) +{ + struct mag_buf *outbuf; + struct mag_buf *lastbuf; + uint32_t slen; + unsigned next_free_buffer; + unsigned free_bufs; + unsigned block_duration; + + static int dropping = 0; + static uint64_t sampleCounter = 0; + + MODES_NOTUSED(ctx); + + // Lock the data buffer variables before accessing them + pthread_mutex_lock(&Modes.data_mutex); + if (Modes.exit) { + LimeSDR.is_stop = true; // ask our caller to exit + } + + next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS; + outbuf = &Modes.mag_buffers[Modes.first_free_buffer]; + lastbuf = &Modes.mag_buffers[(Modes.first_free_buffer + MODES_MAG_BUFFERS - 1) % MODES_MAG_BUFFERS]; + free_bufs = (Modes.first_filled_buffer - next_free_buffer + MODES_MAG_BUFFERS) % MODES_MAG_BUFFERS; + + // Paranoia! Unlikely, but let's go for belt and suspenders here + + if (len != MODES_RTL_BUF_SIZE) { + fprintf(stderr, "weirdness: limesdr gave us a block with an unusual size (got %u bytes, expected %u bytes)\n", + (unsigned)len, (unsigned)MODES_RTL_BUF_SIZE); + + if (len > MODES_RTL_BUF_SIZE) { + // wat?! Discard the start. + unsigned discard = (len - MODES_RTL_BUF_SIZE + 1) / LimeSDR.bytes_in_sample; + outbuf->dropped += discard; + buf += discard * LimeSDR.bytes_in_sample; + len -= discard * LimeSDR.bytes_in_sample; + } + } + + slen = len / LimeSDR.bytes_in_sample; // Drops any trailing odd sample, that's OK + + if (free_bufs == 0 || (dropping && free_bufs < MODES_MAG_BUFFERS/2)) { + // FIFO is full. Drop this block. + dropping = 1; + outbuf->dropped += slen; + sampleCounter += slen; + pthread_mutex_unlock(&Modes.data_mutex); + return; + } + + dropping = 0; + pthread_mutex_unlock(&Modes.data_mutex); + + // Compute the sample timestamp and system timestamp for the start of the block + outbuf->sampleTimestamp = sampleCounter * 12e6 / Modes.sample_rate; + sampleCounter += slen; + + // Get the approx system time for the start of this block + block_duration = 1e3 * slen / Modes.sample_rate; + outbuf->sysTimestamp = mstime() - block_duration; + + // Copy trailing data from last block (or reset if not valid) + if (outbuf->dropped == 0) { + memcpy(outbuf->data, lastbuf->data + lastbuf->length, Modes.trailing_samples * sizeof(uint16_t)); + } else { + memset(outbuf->data, 0, Modes.trailing_samples * sizeof(uint16_t)); + } + + // Convert the new data + outbuf->length = slen; + LimeSDR.converter(buf, &outbuf->data[Modes.trailing_samples], slen, LimeSDR.converter_state, &outbuf->mean_level, &outbuf->mean_power); + + // Push the new data to the demodulation thread + pthread_mutex_lock(&Modes.data_mutex); + + Modes.mag_buffers[next_free_buffer].dropped = 0; + Modes.mag_buffers[next_free_buffer].length = 0; // just in case + Modes.first_free_buffer = next_free_buffer; + + // accumulate CPU while holding the mutex, and restart measurement + end_cpu_timing(&limesdr_thread_cpu, &Modes.reader_cpu_accumulator); + start_cpu_timing(&limesdr_thread_cpu); + + pthread_cond_signal(&Modes.data_cond); + pthread_mutex_unlock(&Modes.data_mutex); +} + +void limesdrRun() +{ + if (!LimeSDR.dev) { + return; + } + + int16_t *buffer = malloc(MODES_RTL_BUF_SIZE); + + LMS_StartStream(&LimeSDR.stream); + + start_cpu_timing(&limesdr_thread_cpu); + + while (!LimeSDR.is_stop) { + int sampleCnt = LMS_RecvStream(&LimeSDR.stream, buffer, MODES_RTL_BUF_SIZE / LimeSDR.bytes_in_sample, NULL, 1000); + if (sampleCnt) { + limesdrCallback((unsigned char *)buffer, sampleCnt * LimeSDR.bytes_in_sample, NULL); + } + } + + if (!Modes.exit) { + fprintf(stderr, "limesdr: async read returned unexpectedly.\n"); + } + + free(buffer); + LMS_StopStream(&LimeSDR.stream); +} + +void limesdrClose() +{ + if (LimeSDR.converter) { + cleanup_converter(LimeSDR.converter_state); + LimeSDR.converter = NULL; + LimeSDR.converter_state = NULL; + } + + LMS_StopStream(&LimeSDR.stream); + + if (LimeSDR.is_stream_opened) { + LMS_DestroyStream(LimeSDR.dev, &LimeSDR.stream); + LimeSDR.is_stream_opened = false; + } + + if (LimeSDR.dev) { + LMS_Close(LimeSDR.dev); + LimeSDR.dev = NULL; + } +} diff --git a/sdr_limesdr.h b/sdr_limesdr.h new file mode 100644 index 0000000..49a2f2d --- /dev/null +++ b/sdr_limesdr.h @@ -0,0 +1,30 @@ +// Part of dump1090, a Mode S message decoder for RTLSDR devices. +// +// sdr_limesdr.h: LimeSDR dongle support (header) +// +// Copyright (c) 2020 Gluttton +// +// 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 . + +#ifndef SDR_LIMESDR_H +#define SDR_LIMESDR_H + +void limesdrInitConfig(); +void limesdrShowHelp(); +bool limesdrOpen(); +void limesdrRun(); +void limesdrClose(); +bool limesdrHandleOption(int argc, char **argv, int *jptr); + +#endif From f314e203422dac5f46c54d9684d237660fbb50e6 Mon Sep 17 00:00:00 2001 From: Gluttton Date: Wed, 29 Jul 2020 23:13:50 +0300 Subject: [PATCH 02/10] limesdr: set verbosity level via input options Add ability to set verbosity level for LimeSDR messages via command line options. The range of available levels is from 0 to 4 and defined by the constants from the `LimeSuite.h` file: - LMS_LOG_CRITICAL 0; - LMS_LOG_ERROR 1; - LMS_LOG_WARNING 2; - LMS_LOG_INFO 3; - LMS_LOG_DEBUG 4. By default the verbosity level is 3 (INFO). Test: launch the program with different verbosity level and ensure that number of messages is changed, for example: $ ./dump1090 --device-type limesdr --limesdr-verbosity 4 $ ./dump1090 --device-type limesdr --limesdr-verbosity 3 $ ./dump1090 --device-type limesdr Signed-off-by: Gluttton --- sdr_limesdr.c | 54 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 17bb81a..5e82806 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -57,6 +57,7 @@ static struct { lms_stream_t stream; bool is_stream_opened; bool is_stop; + char verbosity; int bytes_in_sample; iq_convert_fn converter; struct converter_state *converter_state; @@ -64,11 +65,14 @@ static struct { void limesdrLogHandler(int lvl, const char *msg) { + if (lvl > LimeSDR.verbosity) { + return; + } + FILE *out = NULL; switch (lvl) { default: case LMS_LOG_DEBUG: - return; case LMS_LOG_INFO: out = stdout; break; @@ -92,6 +96,7 @@ void limesdrInitConfig() LimeSDR.stream.dataFmt = LMS_FMT_I16; // should be matched with conveter LimeSDR.is_stream_opened = false; LimeSDR.is_stop = false; + LimeSDR.verbosity = LMS_LOG_INFO; LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 LMS_RegisterLogHandler(limesdrLogHandler); @@ -101,17 +106,23 @@ void limesdrShowHelp() { printf(" limesdr-specific options (use with --device-type limesdr)\n"); printf("\n"); - printf("so far there is no any LimeSDR specific option...\n"); + printf("--limesdr-verbosity set verbosity level for LimeSDR messages\n"); printf("\n"); } bool limesdrHandleOption(int argc, char **argv, int *jptr) { - MODES_NOTUSED(argc); - MODES_NOTUSED(argv); - MODES_NOTUSED(jptr); + int j = *jptr; + bool more = (j + 1 < argc); - return false; + if (!strcmp(argv[j], "--limesdr-verbosity") && more) { + LimeSDR.verbosity = atoi(argv[++j]); + } else { + return false; + } + *jptr = j; + + return true; } bool limesdrOpen(void) @@ -120,64 +131,64 @@ bool limesdrOpen(void) lms_info_str_t list[devCountMax]; const int devCount = LMS_GetDeviceList(list); if (devCount < 0) { - fprintf(stderr, "limesdr: unable to get a number of connected devices\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to get a number of connected devices"); goto error; } if (devCount < 1) { - fprintf(stderr, "limesdr: no connected devices\n"); + limesdrLogHandler(LMS_LOG_ERROR, "no connected devices"); goto error; } if (LMS_Open(&LimeSDR.dev, list[0], NULL) ) { - fprintf(stderr, "limesdr: unable to open device\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to open device"); goto error; } if (LMS_Init(LimeSDR.dev)) { - fprintf(stderr, "limesdr: unable to initialize device\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to initialize device"); goto error; } if (LMS_EnableChannel(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, true)) { - fprintf(stderr, "limesdr: unable to enable RX channel\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to enable RX channel"); goto error; } if (LMS_SetLOFrequency(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.freq)) { - fprintf(stderr, "limesdr: unable to set frequency\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to set frequency"); goto error; } if (LMS_SetAntenna(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LMS_PATH_LNAL)) { - fprintf(stderr, "limesdr: unable to set RF port\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to set RF port"); goto error; } if (LMS_SetSampleRate(LimeSDR.dev, Modes.sample_rate, 0/*default oversample*/)) { - fprintf(stderr, "limesdr: unable to set sampling rate\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to set sampling rate"); goto error; } if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 0.85)) { - fprintf(stderr, "limesdr: unable to set gain\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain"); goto error; } if (LMS_SetLPFBW(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.sample_rate)) { - fprintf(stderr, "limesdr: unable to set LP filter\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to set LP filter"); goto error; } LimeSDR.is_stream_opened = true; if (LMS_SetupStream(LimeSDR.dev, &LimeSDR.stream)) { - fprintf(stderr, "limesdr: unable to setup stream\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to setup stream"); LimeSDR.is_stream_opened = false; goto error; } if (LMS_Calibrate(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 2.5e6/*0.5e5*/, 0)) { - fprintf(stderr, "limesdr: unable to calibrate device\n"); + limesdrLogHandler(LMS_LOG_ERROR, "unable to calibrate device"); goto error; } @@ -186,7 +197,7 @@ bool limesdrOpen(void) Modes.dc_filter, &LimeSDR.converter_state); if (!LimeSDR.converter) { - fprintf(stderr, "limesdr: can't initialize sample converter.\n"); + limesdrLogHandler(LMS_LOG_ERROR, "can't initialize sample converter"); goto error; } @@ -236,8 +247,7 @@ void limesdrCallback(unsigned char *buf, uint32_t len, void *ctx) // Paranoia! Unlikely, but let's go for belt and suspenders here if (len != MODES_RTL_BUF_SIZE) { - fprintf(stderr, "weirdness: limesdr gave us a block with an unusual size (got %u bytes, expected %u bytes)\n", - (unsigned)len, (unsigned)MODES_RTL_BUF_SIZE); + limesdrLogHandler(LMS_LOG_WARNING, "device gave us a block with an unusual size"); if (len > MODES_RTL_BUF_SIZE) { // wat?! Discard the start. @@ -316,7 +326,7 @@ void limesdrRun() } if (!Modes.exit) { - fprintf(stderr, "limesdr: async read returned unexpectedly.\n"); + limesdrLogHandler(LMS_LOG_WARNING, "async read returned unexpectedly"); } free(buffer); From 7267d8aff987648cea214c04b1a24019e04d74b9 Mon Sep 17 00:00:00 2001 From: Gluttton Date: Thu, 30 Jul 2020 01:23:01 +0300 Subject: [PATCH 03/10] limesdr: add ability to select desired device Add ability to select a desired LimeSDR device by serial number. It is not necessary to pass a whole serial number, but its key part is enough. The first device which serial contains the passed key is selected. Test: connect LimeSDR device and try to select it by serial number, below an example for a device with serial 0009081C05C00000: OK: $ ./dump1090 --device-type limesdr --limesdr-serial 9 OK: $ ./dump1090 --device-type limesdr --limesdr-serial 90 OK: $ ./dump1090 --device-type limesdr --limesdr-serial 908 NG: $ ./dump1090 --device-type limesdr --limesdr-serial 999 It hasn't been tested with several devices! Signed-off-by: Gluttton --- sdr_limesdr.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 5e82806..21d8dde 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -58,6 +58,7 @@ static struct { bool is_stream_opened; bool is_stop; char verbosity; + lms_info_str_t serial; int bytes_in_sample; iq_convert_fn converter; struct converter_state *converter_state; @@ -97,6 +98,7 @@ void limesdrInitConfig() LimeSDR.is_stream_opened = false; LimeSDR.is_stop = false; LimeSDR.verbosity = LMS_LOG_INFO; + LimeSDR.serial[0] = '\0'; LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 LMS_RegisterLogHandler(limesdrLogHandler); @@ -107,6 +109,7 @@ void limesdrShowHelp() printf(" limesdr-specific options (use with --device-type limesdr)\n"); printf("\n"); printf("--limesdr-verbosity set verbosity level for LimeSDR messages\n"); + printf("--limesdr-serial serial number of desired device\n"); printf("\n"); } @@ -117,6 +120,8 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) if (!strcmp(argv[j], "--limesdr-verbosity") && more) { LimeSDR.verbosity = atoi(argv[++j]); + } else if (!strcmp(argv[j], "--limesdr-serial") && more) { + strcpy(LimeSDR.serial, argv[++j]); } else { return false; } @@ -140,7 +145,32 @@ bool limesdrOpen(void) goto error; } - if (LMS_Open(&LimeSDR.dev, list[0], NULL) ) { + limesdrLogHandler(LMS_LOG_INFO, "connected devices:"); + for (int i = 0; i < devCount; ++i) { + limesdrLogHandler(LMS_LOG_INFO, list[i]); + } + + bool isDevMatched = !strlen(LimeSDR.serial); + int devIndex = 0; + const char *serialTag = "serial="; + for (int i = 0; i < devCount && !isDevMatched; ++i) { + const char *serial = strstr(list[i], serialTag); + if (serial) { + if (strstr(serial + strlen(serialTag), LimeSDR.serial)) { + isDevMatched = true; + devIndex = i; + } + } + } + if (isDevMatched) { + limesdrLogHandler(LMS_LOG_INFO, "selected device:"); + limesdrLogHandler(LMS_LOG_INFO, list[devIndex]); + } else { + limesdrLogHandler(LMS_LOG_ERROR, "unable to find desired device"); + goto error; + } + + if (LMS_Open(&LimeSDR.dev, list[devIndex], NULL) ) { limesdrLogHandler(LMS_LOG_ERROR, "unable to open device"); goto error; } From eb476d2e756a54abf290e5b693e89cf27ffea2db Mon Sep 17 00:00:00 2001 From: Gluttton Date: Thu, 30 Jul 2020 22:44:45 +0300 Subject: [PATCH 04/10] limesdr: add ability to select RX channel Add ability to select an RX channel by number. By default channel 0 is used. Test: connect LimeSDR device and try to select the RX channel by number: OK: $ ./dump1090 --device-type limesdr --limesdr-channel 0 OK: $ ./dump1090 --device-type limesdr --limesdr-channel 1 NG: $ ./dump1090 --device-type limesdr --limesdr-channel 2 $ limesdr: Invalid channel number. Signed-off-by: Gluttton --- sdr_limesdr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 21d8dde..c9dd581 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -110,6 +110,7 @@ void limesdrShowHelp() printf("\n"); printf("--limesdr-verbosity set verbosity level for LimeSDR messages\n"); printf("--limesdr-serial serial number of desired device\n"); + printf("--limesdr-channel set number of an RX channel\n"); printf("\n"); } @@ -122,6 +123,8 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) LimeSDR.verbosity = atoi(argv[++j]); } else if (!strcmp(argv[j], "--limesdr-serial") && more) { strcpy(LimeSDR.serial, argv[++j]); + } else if (!strcmp(argv[j], "--limesdr-channel") && more) { + LimeSDR.stream.channel = atoi(argv[++j]); } else { return false; } From da1aeeeea68ccf37332347918fd040129c591e6b Mon Sep 17 00:00:00 2001 From: Gluttton Date: Thu, 30 Jul 2020 23:08:32 +0300 Subject: [PATCH 05/10] limesdr: add ability to set RF oversampling ratio Add ability to set RF oversampling ratio via command line options. By default the default value is used. Test: none. Signed-off-by: Gluttton --- sdr_limesdr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index c9dd581..770edba 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -58,6 +58,7 @@ static struct { bool is_stream_opened; bool is_stop; char verbosity; + size_t oversample; lms_info_str_t serial; int bytes_in_sample; iq_convert_fn converter; @@ -98,6 +99,7 @@ void limesdrInitConfig() LimeSDR.is_stream_opened = false; LimeSDR.is_stop = false; LimeSDR.verbosity = LMS_LOG_INFO; + LimeSDR.oversample = 0; // default oversample LimeSDR.serial[0] = '\0'; LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 @@ -111,6 +113,7 @@ void limesdrShowHelp() printf("--limesdr-verbosity set verbosity level for LimeSDR messages\n"); printf("--limesdr-serial serial number of desired device\n"); printf("--limesdr-channel set number of an RX channel\n"); + printf("--limesdr-oversample set RF oversampling ratio\n"); printf("\n"); } @@ -125,6 +128,8 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) strcpy(LimeSDR.serial, argv[++j]); } else if (!strcmp(argv[j], "--limesdr-channel") && more) { LimeSDR.stream.channel = atoi(argv[++j]); + } else if (!strcmp(argv[j], "--limesdr-oversample") && more) { + LimeSDR.oversample = atoi(argv[++j]); } else { return false; } @@ -198,7 +203,7 @@ bool limesdrOpen(void) goto error; } - if (LMS_SetSampleRate(LimeSDR.dev, Modes.sample_rate, 0/*default oversample*/)) { + if (LMS_SetSampleRate(LimeSDR.dev, Modes.sample_rate, LimeSDR.oversample)) { limesdrLogHandler(LMS_LOG_ERROR, "unable to set sampling rate"); goto error; } From c32ed2866ef4e316f769bf0f217cabb736aaab4d Mon Sep 17 00:00:00 2001 From: Gluttton Date: Thu, 30 Jul 2020 23:22:15 +0300 Subject: [PATCH 06/10] limesdr: add ability to set normalized gain Add ability to set the combined normalized gain via command line options. By default the gain is equal to 0.75. Test: connect LimeSDR device, try to set different gain and check logs: $ ./dump1090 --device-type limesdr --limesdr-gain 0.01 $ ./dump1090 --device-type limesdr --limesdr-gain 0.5 $ ./dump1090 --device-type limesdr --limesdr-gain 0.99 Signed-off-by: Gluttton --- sdr_limesdr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 770edba..757fbae 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -59,6 +59,7 @@ static struct { bool is_stop; char verbosity; size_t oversample; + float gain; lms_info_str_t serial; int bytes_in_sample; iq_convert_fn converter; @@ -100,6 +101,7 @@ void limesdrInitConfig() LimeSDR.is_stop = false; LimeSDR.verbosity = LMS_LOG_INFO; LimeSDR.oversample = 0; // default oversample + LimeSDR.gain = 0.75; LimeSDR.serial[0] = '\0'; LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 @@ -114,6 +116,7 @@ void limesdrShowHelp() printf("--limesdr-serial serial number of desired device\n"); printf("--limesdr-channel set number of an RX channel\n"); printf("--limesdr-oversample set RF oversampling ratio\n"); + printf("--limesdr-gain set normalized gain\n"); printf("\n"); } @@ -130,6 +133,8 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) LimeSDR.stream.channel = atoi(argv[++j]); } else if (!strcmp(argv[j], "--limesdr-oversample") && more) { LimeSDR.oversample = atoi(argv[++j]); + } else if (!strcmp(argv[j], "--limesdr-gain") && more) { + LimeSDR.gain = atof(argv[++j]); } else { return false; } @@ -208,7 +213,7 @@ bool limesdrOpen(void) goto error; } - if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 0.85)) { + if (LMS_SetNormalizedGain(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LimeSDR.gain)) { limesdrLogHandler(LMS_LOG_ERROR, "unable to set gain"); goto error; } From 95ae1a92be169fda5668bd1745dbf44529959dbd Mon Sep 17 00:00:00 2001 From: Gluttton Date: Thu, 30 Jul 2020 23:45:14 +0300 Subject: [PATCH 07/10] limesdr: add ability to set LPF bandwidth Add ability to set LPF bandwidth via input command line options. By default the bandwidth is equal to the default sample rate 2.4 MHz. Test: connect LimeSDR device, try to set different bandwidth and check logs: $ ./dump1090 --device-type limesdr --limesdr-lpfbw 2500000 $ ./dump1090 --device-type limesdr --limesdr-lpfbw 500000 Signed-off-by: Gluttton --- sdr_limesdr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 757fbae..1794418 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -60,6 +60,7 @@ static struct { char verbosity; size_t oversample; float gain; + float lpfbw; lms_info_str_t serial; int bytes_in_sample; iq_convert_fn converter; @@ -102,6 +103,7 @@ void limesdrInitConfig() LimeSDR.verbosity = LMS_LOG_INFO; LimeSDR.oversample = 0; // default oversample LimeSDR.gain = 0.75; + LimeSDR.lpfbw = 2400000.0; LimeSDR.serial[0] = '\0'; LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 @@ -117,6 +119,7 @@ void limesdrShowHelp() printf("--limesdr-channel set number of an RX channel\n"); printf("--limesdr-oversample set RF oversampling ratio\n"); printf("--limesdr-gain set normalized gain\n"); + printf("--limesdr-lpfbw set LPF bandwidth\n"); printf("\n"); } @@ -135,6 +138,8 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) LimeSDR.oversample = atoi(argv[++j]); } else if (!strcmp(argv[j], "--limesdr-gain") && more) { LimeSDR.gain = atof(argv[++j]); + } else if (!strcmp(argv[j], "--limesdr-lpfbw") && more) { + LimeSDR.lpfbw = atof(argv[++j]); } else { return false; } @@ -218,7 +223,7 @@ bool limesdrOpen(void) goto error; } - if (LMS_SetLPFBW(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.sample_rate)) { + if (LMS_SetLPFBW(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LimeSDR.lpfbw)) { limesdrLogHandler(LMS_LOG_ERROR, "unable to set LP filter"); goto error; } From bb158d929ce2ea42a469487a4ae438258a59ffaa Mon Sep 17 00:00:00 2001 From: Gluttton Date: Fri, 31 Jul 2020 00:06:33 +0300 Subject: [PATCH 08/10] limesdr: add ability to set bandwidth Add ability to set calibration bandwidth via input command line options. By default the bandwidth is equal to 2.5 MHz. Test: connect LimeSDR device, try to set different bandwidth and check logs: $ ./dump1090 --device-type limesdr --limesdr-bw 5000000 $ ./dump1090 --device-type limesdr --limesdr-bw 500000 Signed-off-by: Gluttton --- sdr_limesdr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 1794418..773c2bd 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -61,6 +61,7 @@ static struct { size_t oversample; float gain; float lpfbw; + float bw; lms_info_str_t serial; int bytes_in_sample; iq_convert_fn converter; @@ -104,6 +105,7 @@ void limesdrInitConfig() LimeSDR.oversample = 0; // default oversample LimeSDR.gain = 0.75; LimeSDR.lpfbw = 2400000.0; + LimeSDR.bw = 2.5e6; // the minimal supported value LimeSDR.serial[0] = '\0'; LimeSDR.bytes_in_sample = 2 * sizeof(int16_t); // hardcoded for LMS_FMT_I16 @@ -120,6 +122,7 @@ void limesdrShowHelp() printf("--limesdr-oversample set RF oversampling ratio\n"); printf("--limesdr-gain set normalized gain\n"); printf("--limesdr-lpfbw set LPF bandwidth\n"); + printf("--limesdr-bw set bandwidth\n"); printf("\n"); } @@ -140,6 +143,8 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) LimeSDR.gain = atof(argv[++j]); } else if (!strcmp(argv[j], "--limesdr-lpfbw") && more) { LimeSDR.lpfbw = atof(argv[++j]); + } else if (!strcmp(argv[j], "--limesdr-bw") && more) { + LimeSDR.bw = atof(argv[++j]); } else { return false; } @@ -235,7 +240,7 @@ bool limesdrOpen(void) goto error; } - if (LMS_Calibrate(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, 2.5e6/*0.5e5*/, 0)) { + if (LMS_Calibrate(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LimeSDR.bw, 0)) { limesdrLogHandler(LMS_LOG_ERROR, "unable to calibrate device"); goto error; } From b70898cd2717b33b592ac1b4e8e9ea13f708aa4d Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Mon, 3 Aug 2020 15:17:29 +0800 Subject: [PATCH 09/10] Placate -Wmissing-declarations --- sdr_limesdr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index 773c2bd..a240ce8 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -68,7 +68,7 @@ static struct { struct converter_state *converter_state; } LimeSDR; -void limesdrLogHandler(int lvl, const char *msg) +static void limesdrLogHandler(int lvl, const char *msg) { if (lvl > LimeSDR.verbosity) { return; @@ -272,7 +272,7 @@ bool limesdrOpen(void) static struct timespec limesdr_thread_cpu; -void limesdrCallback(unsigned char *buf, uint32_t len, void *ctx) +static void limesdrCallback(unsigned char *buf, uint32_t len, void *ctx) { struct mag_buf *outbuf; struct mag_buf *lastbuf; From 9520740a12f7bdd44723920061eb25bbc181d45e Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Mon, 3 Aug 2020 18:02:27 +0800 Subject: [PATCH 10/10] limesdr: try to select an appropriate antenna based on the limesuite antenna metadata. --- sdr_limesdr.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/sdr_limesdr.c b/sdr_limesdr.c index a240ce8..d55ae98 100644 --- a/sdr_limesdr.c +++ b/sdr_limesdr.c @@ -153,6 +153,51 @@ bool limesdrHandleOption(int argc, char **argv, int *jptr) return true; } +static size_t selectAntenna() +{ + int result = LMS_PATH_AUTO; + lms_name_t *names = NULL; + + int numAntennas = LMS_GetAntennaList(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, NULL); + if (numAntennas <= 0) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to get antenna list"); + goto done; + } + + names = calloc(numAntennas, sizeof(lms_name_t)); + if (!names) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to get antenna list"); + goto done; + } + + numAntennas = LMS_GetAntennaList(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, names); + if (numAntennas < 0) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to get antenna list"); + goto done; + } + + for (int i = 0; i < numAntennas; ++i) { + lms_range_t range; + if (LMS_GetAntennaBW(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, i, &range) < 0) { + fprintf(stderr, "limesdr: unable to get antenna bandwidth for antenna %d (%s)", i, names[i]); + continue; + } + + if (range.min <= Modes.freq && range.max >= Modes.freq) { + fprintf(stderr, "limesdr: selected rx antenna %d (%s) with bandwidth %.1f .. %.1fMHz", i, names[i], range.min / 1e6, range.max / 1e6); + result = i; + goto done; + } + } + + done: + if (result == LMS_PATH_AUTO) + limesdrLogHandler(LMS_LOG_INFO, "limesdr: no suitable antenna found, letting LimeSuite do automatic antenna selection"); + if (names) + free(names); + return result; +} + bool limesdrOpen(void) { const size_t devCountMax = 8; @@ -208,13 +253,13 @@ bool limesdrOpen(void) goto error; } - if (LMS_SetLOFrequency(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.freq)) { - limesdrLogHandler(LMS_LOG_ERROR, "unable to set frequency"); + if (LMS_SetAntenna(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, selectAntenna())) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to set RF port"); goto error; } - if (LMS_SetAntenna(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, LMS_PATH_LNAL)) { - limesdrLogHandler(LMS_LOG_ERROR, "unable to set RF port"); + if (LMS_SetLOFrequency(LimeSDR.dev, LMS_CH_RX, LimeSDR.stream.channel, Modes.freq)) { + limesdrLogHandler(LMS_LOG_ERROR, "unable to set frequency"); goto error; }