diff --git a/CMakeLists.txt b/CMakeLists.txt index df28a6ecb..2de10e807 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,8 @@ option(ENABLE_UHD "Enable the use of UHD (driver for all USRP devices)" ON) option(ENABLE_OSMOSDR "Enable the use of OsmoSDR and other front-ends (RTL-based dongles, HackRF, bladeRF, etc.) as signal source" OFF) +option(ENABLE_LIMESDR "Enable the use of LimeSDR and Custom LimeSDR as signal source" OFF) + option(ENABLE_FMCOMMS2 "Enable the use of FMCOMMS4-EBZ + ZedBoard hardware, requires gr-iio" OFF) option(ENABLE_PLUTOSDR "Enable the use of ADALM-PLUTO Evaluation Boards (Analog Devices Inc.), requires gr-iio" OFF) @@ -2891,6 +2893,33 @@ else() endif() +########################################## +# gr-limesdr - OPTIONAL +# https://github.com/myriadrf/gr-limesdr +########################################## +find_package(GRLIMESDR) +set_package_properties(limesdr PROPERTIES + PURPOSE "Used for communication with LimeSDR." + TYPE OPTIONAL +) +if(ENABLE_LIMESDR) + if(GRLIMESDR_FOUND) + message(STATUS "The driver for LimeSDR will be compiled.") + message(STATUS " You can disable it with 'cmake -DENABLE_LIMESDR=OFF ..'") + else() + if(ENABLE_PACKAGING) + message(WARNING "gr-limesdr has not been found. Source blocks depending on it will NOT be built.") + else() + message(FATAL_ERROR "gr-limesdr required to build gnss-sdr with the optional LIMESDR driver") + endif() + set(ENABLE_LIMESDR OFF) + endif() +else() + message(STATUS "The (optional) driver for LimeSDR is not enabled.") + message(STATUS " Enable it with 'cmake -DENABLE_LIMESDR=ON ..' to add support for LimeSDR.") +endif() + + ############################################## # gr-iio - OPTIONAL # IIO blocks for GNU Radio @@ -3219,6 +3248,7 @@ add_subdirectory(src) ################################################################################ add_feature_info(ENABLE_UHD ENABLE_UHD "Enables UHD_Signal_Source for using RF front-ends from the USRP family. Requires gr-uhd.") add_feature_info(ENABLE_OSMOSDR ENABLE_OSMOSDR "Enables Osmosdr_Signal_Source and RtlTcp_Signal_Source for using RF front-ends compatible with the OsmoSDR driver. Requires gr-osmosdr.") +add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. Requires gr-limesdr.") add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.") add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") diff --git a/cmake/Modules/FindGRLIMESDR.cmake b/cmake/Modules/FindGRLIMESDR.cmake new file mode 100644 index 000000000..3c4d41782 --- /dev/null +++ b/cmake/Modules/FindGRLIMESDR.cmake @@ -0,0 +1,151 @@ +# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +# This file is part of GNSS-SDR. +# +# SPDX-FileCopyrightText: 2011-2020 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-License-Identifier: BSD-3-Clause + +# Tries to find gr-limesdr. +# +# Usage of this module as follows: +# +# find_package(GRLIMESDR) +# +# Variables used by this module, they can change the default behaviour and need +# to be set before calling find_package: +# +# GrLimeSDR_ROOT_DIR Set this variable to the root installation of +# gr-limesdr if the module has problems finding +# the proper installation path. +# +# Variables defined by this module: +# +# GRLIMESDR_FOUND System has gr-limesdr libs/headers +# GRLIMESDR_LIBRARIES The gr-limesdr libraries (gnuradio-limesdr) +# GRLIMESDR_INCLUDE_DIR The location of gr-limesdr headers +# +# Provides the following imported target: +# Gnuradio::limesdr +# + +if(NOT COMMAND feature_summary) + include(FeatureSummary) +endif() + +if(NOT PKG_CONFIG_FOUND) + include(FindPkgConfig) +endif() + +pkg_check_modules(GRLIMESDR_PKG gnuradio-limesdr) + +if(NOT GRLIMESDR_ROOT) + set(GRLIMESDR_ROOT_USER_DEFINED /usr) +else() + set(GRLIMESDR_ROOT_USER_DEFINED ${GRLIMESDR_ROOT}) +endif() +if(DEFINED ENV{GRLIMESDR_ROOT}) + set(GRLIMESDR_ROOT_USER_DEFINED + ${GRLIMESDR_ROOT_USER_DEFINED} + $ENV{GRLIMESDR_ROOT} + ) +endif() + +find_path(GRLIMESDR_INCLUDE_DIR + NAMES + limesdr/source.h + limesdr/api.h + HINTS + ${GRLIMESDR_PKG_INCLUDEDIR} + PATHS + ${GRLIMESDR_ROOT_USER_DEFINED}/include + /usr/include + /usr/local/include + /opt/local/include +) + +find_library(GRLIMESDR_LIBRARIES + NAMES + gnuradio-limesdr + HINTS + ${GRLIMESDR_PKG_LIBDIR} + PATHS + ${GRLIMESDR_ROOT_USER_DEFINED}/lib + ${GRLIMESDR_ROOT_USER_DEFINED}/lib64 + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/aarch64-linux-gnu + /usr/lib/mipsel-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/hppa-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/i386-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/riscv64-linux-gnu + /usr/lib/alpha-linux-gnu + /usr/local/lib + /usr/local/lib64 + /opt/local/lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GRLIMESDR DEFAULT_MSG GRLIMESDR_LIBRARIES GRLIMESDR_INCLUDE_DIR) + +if(GRLIMESDR_PKG_VERSION) + set(GRLIMESDR_VERSION_AUX ${GRLIMESDR_PKG_VERSION}) + string(REGEX REPLACE "^v" "" GRLIMESDR_VERSION ${GRLIMESDR_VERSION_AUX}) +endif() + +set_package_properties(GRLIMESDR PROPERTIES + URL "https://github.com/myriadrf/gr-limesdr" +) + +if(GRLIMESDR_FOUND AND GRLIMESDR_VERSION) + set_package_properties(GRLIMESDR PROPERTIES + DESCRIPTION "limesdr GNU Radio blocks (found: v${GRLIMESDR_VERSION})" + ) +else() + set_package_properties(GRLIMESDR PROPERTIES + DESCRIPTION "limesdr GNU Radio blocks" + ) +endif() + +if(GRLIMESDR_FOUND AND NOT TARGET Gnuradio::limesdr) + add_library(Gnuradio::limesdr SHARED IMPORTED) + set_target_properties(Gnuradio::limesdr PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GRLIMESDR_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${GRLIMESDR_INCLUDE_DIR};${GRLIMESDR_INCLUDE_DIR}/limesdr" + INTERFACE_LINK_LIBRARIES "${GRLIMESDR_LIBRARIES}" + ) + + #check for PPS custom version + file(READ ${GRLIMESDR_INCLUDE_DIR}/limesdr/source.h TMPTXT) + + string(FIND "${TMPTXT}" "enable_PPS_mode" matchres) + + message(STATUS ${matchres}) + + if(${matchres} EQUAL -1) + message("Using standard gr-limesdr library ") + else() + set(GRLIMESDR_PPS True) + message("Using custom gr-limesdr library with PPS support ") + endif () + +endif() + +mark_as_advanced(GRLIMESDR_LIBRARIES GRLIMESDR_INCLUDE_DIR) diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index 3bd766ff1..03b87e8ca 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -84,6 +84,14 @@ if(ENABLE_OSMOSDR) endif() endif() +if(ENABLE_LIMESDR) + if(GRLIMESDR_FOUND) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} limesdr_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} limesdr_signal_source.h) + endif() +endif() + + if(ENABLE_UHD) set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} uhd_signal_source.cc) @@ -191,6 +199,14 @@ if(ENABLE_OSMOSDR AND GROSMOSDR_FOUND) ) endif() +if(ENABLE_LIMESDR AND GRLIMESDR_FOUND) + target_link_libraries(signal_source_adapters + PUBLIC + Gnuradio::limesdr + ) +endif() + + if(ENABLE_AD9361 AND LIBIIO_FOUND) target_link_libraries(signal_source_adapters PRIVATE @@ -255,6 +271,11 @@ if(ENABLE_PLUTOSDR OR ENABLE_FMCOMMS2) endif() endif() + if(GRLIMESDR_PPS) + target_compile_definitions(signal_source_adapters PUBLIC -DLimeSDR_PPS=1) + endif() + + if(ENABLE_CLANG_TIDY) if(CLANG_TIDY_EXE) set_target_properties(signal_source_adapters @@ -268,6 +289,8 @@ target_compile_definitions(signal_source_adapters PRIVATE -DGNSSSDR_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}" ) + + set_property(TARGET signal_source_adapters APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES $ diff --git a/src/algorithms/signal_source/adapters/limesdr_signal_source.cc b/src/algorithms/signal_source/adapters/limesdr_signal_source.cc new file mode 100644 index 000000000..cce902b98 --- /dev/null +++ b/src/algorithms/signal_source/adapters/limesdr_signal_source.cc @@ -0,0 +1,220 @@ +/*! + * \file limesdr_signal_source.cc + * \brief Signal source for LimeSDR front-end + * \author Javier Arribas, 2021. jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "limesdr_signal_source.h" +#include "configuration_interface.h" +#include "gnss_sdr_valve.h" +#include +#include +#include +#include + + +LimesdrSignalSource::LimesdrSignalSource(const ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, unsigned int out_stream, + Concurrent_Queue* queue) : role_(role), in_stream_(in_stream), out_stream_(out_stream) +{ + // DUMP PARAMETERS + const std::string empty; + const std::string default_dump_file("./data/signal_source.dat"); + const std::string default_item_type("gr_complex"); + samples_ = configuration->property(role + ".samples", static_cast(0)); + dump_ = configuration->property(role + ".dump", false); + dump_filename_ = configuration->property(role + ".dump_filename", + default_dump_file); + + // Driver parameters + channel_ = configuration->property(role + ".channel", 0); + //AGC_enabled_ = configuration->property(role + ".AGC_enabled", true); + freq_ = configuration->property(role + ".freq", 1575420000); + gain_ = configuration->property(role + ".gain", 40.0); + sample_rate_ = configuration->property(role + ".sampling_frequency", 2.0e6); + //todo: check aif bw is within limits + analog_bw_hz_ = configuration->property(role + ".analog_bw", sample_rate_); + digital_bw_hz_ = configuration->property(role + ".digital_bw", sample_rate_); + item_type_ = configuration->property(role + ".item_type", default_item_type); + limesdr_serial_ = configuration->property(role + ".limesdr_serial_", std::string()); + limesdr_file_ = configuration->property(role + ".limesdr_file_", std::string()); + antenna_ = configuration->property(role + ".antenna", 255); + + PPS_mode_ = configuration->property(role + ".PPS_mode", false); + //channel_mode Channel and mode selection A(1), B(2), (A+B)MIMO(3). + limechannel_mode_ = configuration->property(role + ".limechannel_mode", 1); + + + if (item_type_ == "short") + { + item_size_ = sizeof(int16_t); + } + else if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + //1. Make the driver instance + + try + { +#ifdef LimeSDR_PPS + limesdr_source_ = gr::limesdr::source::make(limesdr_serial_, limechannel_mode_, limesdr_file_, PPS_mode_); +#else + limesdr_source_ = gr::limesdr::source::make(limesdr_serial_, limechannel_mode_, limesdr_file_); +#endif + } + catch (const boost::exception& e) + { + LOG(WARNING) << "Boost exception: " << boost::diagnostic_information(e); + throw std::invalid_argument("Wrong LimeSDR arguments"); + } + + // For LimeSDR: Set RX antenna + /** + * Set which antenna is used + * + * @param antenna Antenna to set: None(0), LNAH(1), LNAL(2), LNAW(3), AUTO(255) + * + * @param channel Channel selection: A(LMS_CH_0),B(LMS_CH_1). + */ + + limesdr_source_->set_antenna(antenna_, channel_); + // 2 set sampling rate + double actual_sample_rate = limesdr_source_->set_sample_rate(sample_rate_); + std::cout << "Actual RX Rate: " << actual_sample_rate << " [SPS]...\n"; + LOG(INFO) << "Actual RX Rate: " << actual_sample_rate << " [SPS]..."; + + // 3. set rx frequency + double actual_center_freq = limesdr_source_->set_center_freq(freq_); + + std::cout << "Actual RX Freq: " << actual_center_freq << " [Hz]...\n"; + LOG(INFO) << "Actual RX Freq: " << actual_center_freq << " [Hz]..."; + + // TODO: Assign the remnant IF from the PLL tune error + std::cout << "PLL Frequency tune error: " << actual_center_freq - freq_ << " [Hz]...\n"; + LOG(INFO) << "PLL Frequency tune error: " << actual_center_freq - freq_ << " [Hz]...\n"; + + + // TODO: gr-limesdr does not report PLL tune frequency error... + + // 4. set rx gain + //todo: gr-limesdr does not expose AGC controls.. + // if (AGC_enabled_ == true) + // { + // osmosdr_source_->set_gain_mode(true); + // std::cout << "AGC enabled\n"; + // LOG(INFO) << "AGC enabled"; + // } + // else + // { + double actual_gain = limesdr_source_->set_gain(gain_, channel_); + std::cout << "Actual RX Gain: " << actual_gain << " [dB]...\n"; + LOG(INFO) << "Actual RX Gain: " << actual_gain << " [dB]..."; + + // Set analog bandwidth + double actual_analog_bw = limesdr_source_->set_bandwidth(analog_bw_hz_, channel_); + std::cout << "Actual Analog Bandwidth: " << actual_analog_bw << " [Hz]...\n"; + + // Set digital bandwidth + limesdr_source_->set_digital_filter(digital_bw_hz_, channel_); + } + else + { + LOG(WARNING) << item_type_ << " unrecognized item type. Using short."; + item_size_ = sizeof(int16_t); + } + + if (samples_ != 0) + { + DLOG(INFO) << "Send STOP signal after " << samples_ << " samples"; + valve_ = gnss_sdr_make_valve(item_size_, samples_, queue); + DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; + } + + if (dump_) + { + DLOG(INFO) << "Dumping output into file " << dump_filename_; + file_sink_ = gr::blocks::file_sink::make(item_size_, dump_filename_.c_str()); + DLOG(INFO) << "file_sink(" << file_sink_->unique_id() << ")"; + } + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +void LimesdrSignalSource::connect(gr::top_block_sptr top_block) +{ + if (samples_ != 0) + { + top_block->connect(limesdr_source_, 0, valve_, 0); + DLOG(INFO) << "connected limesdr source to valve"; + if (dump_) + { + top_block->connect(valve_, 0, file_sink_, 0); + DLOG(INFO) << "connected valve to file sink"; + } + } + else + { + if (dump_) + { + top_block->connect(limesdr_source_, 0, file_sink_, 0); + DLOG(INFO) << "connected limesdr source to file sink"; + } + } +} + + +void LimesdrSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (samples_ != 0) + { + top_block->disconnect(limesdr_source_, 0, valve_, 0); + if (dump_) + { + top_block->disconnect(valve_, 0, file_sink_, 0); + } + } + else + { + if (dump_) + { + top_block->disconnect(limesdr_source_, 0, file_sink_, 0); + } + } +} + + +gr::basic_block_sptr LimesdrSignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return gr::basic_block_sptr(); +} + + +gr::basic_block_sptr LimesdrSignalSource::get_right_block() +{ + if (samples_ != 0) + { + return valve_; + } + else + { + return limesdr_source_; + } +} diff --git a/src/algorithms/signal_source/adapters/limesdr_signal_source.h b/src/algorithms/signal_source/adapters/limesdr_signal_source.h new file mode 100644 index 000000000..2a5baf33b --- /dev/null +++ b/src/algorithms/signal_source/adapters/limesdr_signal_source.h @@ -0,0 +1,109 @@ +/*! + * \file limesdr_signal_source.cc + * \brief Signal source for LimeSDR front-end + * \author Javier Arribas, 2021. jarribas(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2021 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_LIMESDR_SIGNAL_SOURCE_H +#define GNSS_SDR_LIMESDR_SIGNAL_SOURCE_H + +#include "concurrent_queue.h" +#include "gnss_block_interface.h" +#include +#include +#include +#include +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + + +class ConfigurationInterface; + +/*! + * \brief This class instantiates the LimeSDR gnuradio signal source. + * It has support also for a customized LimeSDR firmware and signal source to support PPS samplestamp reading. + */ +class LimesdrSignalSource : public GNSSBlockInterface +{ +public: + LimesdrSignalSource(const ConfigurationInterface* configuration, + const std::string& role, unsigned int in_stream, + unsigned int out_stream, Concurrent_Queue* queue); + + ~LimesdrSignalSource() = default; + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Osmosdr_Signal_Source" + */ + inline std::string implementation() override + { + return "Limesdr_Signal_Source"; + } + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + gr::limesdr::source::sptr limesdr_source_; + gnss_shared_ptr valve_; + gr::blocks::file_sink::sptr file_sink_; + + std::string role_; + std::string item_type_; + std::string dump_filename_; + std::string limesdr_serial_; + std::string limesdr_file_; + int antenna_; + int channel_; + + // Front-end settings + double sample_rate_; + double freq_; + double gain_; + double analog_bw_hz_; + double digital_bw_hz_; + size_t item_size_; + int64_t samples_; + + unsigned int in_stream_; + unsigned int out_stream_; + + int limechannel_mode_; + + bool PPS_mode_; + //bool AGC_enabled_; + bool dump_; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_LIMESDR_SIGNAL_SOURCE_H