diff --git a/CMakeLists.txt b/CMakeLists.txt index dec1a3edb..80492950d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,7 +143,7 @@ if(NOT ${THIS_IS_A_RELEASE}) find_package(Git) set_package_properties(Git PROPERTIES URL "https://git-scm.com" - DESCRIPTION "A free and open source distributed version control system" + DESCRIPTION "A free and open source distributed version control system (found: ${GIT_VERSION_STRING})" PURPOSE "Manage version control, get MINOR_VERSION name for version number." TYPE REQUIRED ) @@ -610,16 +610,31 @@ set(GR_REQUIRED_COMPONENTS RUNTIME PMT BLOCKS FFT FILTER ANALOG) find_package(UHD) set_package_properties(UHD PROPERTIES URL "https://www.ettus.com/sdr-software/detail/usrp-hardware-driver" - DESCRIPTION "USRP Hardware Driver" PURPOSE "Used for communication with front-ends of the USRP family." TYPE OPTIONAL ) if(ENABLE_UHD) if(NOT UHD_FOUND) set(ENABLE_UHD OFF) + set_package_properties(UHD PROPERTIES + DESCRIPTION "USRP Hardware Driver" + ) else() set(GR_REQUIRED_COMPONENTS ${GR_REQUIRED_COMPONENTS} UHD) + if(UHD_VERSION) + set_package_properties(UHD PROPERTIES + DESCRIPTION "USRP Hardware Driver (found: v${UHD_VERSION})" + ) + else() + set_package_properties(UHD PROPERTIES + DESCRIPTION "USRP Hardware Driver" + ) + endif() endif() +else() + set_package_properties(UHD PROPERTIES + DESCRIPTION "USRP Hardware Driver" + ) endif() find_package(GNURADIO) @@ -809,15 +824,15 @@ endif() # VOLK - Vector-Optimized Library of Kernels ################################################################################ find_package(VOLK) -set_package_properties(VOLK PROPERTIES - URL "http://libvolk.org" - DESCRIPTION "Vector-Optimized Library of Kernels" - PURPOSE "Provides an abstraction of optimized math routines targeting several SIMD processors." - TYPE REQUIRED -) if(NOT VOLK_FOUND) message(FATAL_ERROR "*** VOLK is required to build gnss-sdr") endif() +set_package_properties(VOLK PROPERTIES + URL "http://libvolk.org" + DESCRIPTION "Vector-Optimized Library of Kernels (found: ${VOLK_VERSION})" + PURPOSE "Provides an abstraction of optimized math routines targeting several SIMD processors." + TYPE REQUIRED +) @@ -875,26 +890,32 @@ if(NOT VOLKGNSSSDR_FOUND) message(FATAL_ERROR "six - python 2 and 3 compatibility library required to build VOLK_GNSSSDR") endif() - set_package_properties(Python3 PROPERTIES - URL "https://www.python.org/" - DESCRIPTION "An interpreted, high-level, general-purpose programming language" - PURPOSE "Required to build volk_gnsssdr." - TYPE REQUIRED - ) + if(Python3_FOUND) + set_package_properties(Python3 PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "An interpreted, high-level, general-purpose programming language (found: ${Python3_VERSION})" + PURPOSE "Required to build volk_gnsssdr." + TYPE REQUIRED + ) + endif() - set_package_properties(Python2 PROPERTIES - URL "https://www.python.org/" - DESCRIPTION "An interpreted, high-level, general-purpose programming language" - PURPOSE "Required to build volk_gnsssdr." - TYPE REQUIRED - ) + if(Python2_FOUND) + set_package_properties(Python2 PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "An interpreted, high-level, general-purpose programming language (found: ${Python2_VERSION})" + PURPOSE "Required to build volk_gnsssdr." + TYPE REQUIRED + ) + endif() - set_package_properties(PythonInterp PROPERTIES - URL "https://www.python.org/" - DESCRIPTION "An interpreted, high-level, general-purpose programming language" - PURPOSE "Required to build volk_gnsssdr." - TYPE REQUIRED - ) + if(PYTHONINTERP_FOUND) + set_package_properties(PythonInterp PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "An interpreted, high-level, general-purpose programming language (found: ${PYTHON_VERSION_STRING})" + PURPOSE "Required to build volk_gnsssdr." + TYPE REQUIRED + ) + endif() set(READ_ENVIRO "") if(ENABLE_PACKAGING) @@ -1343,7 +1364,6 @@ endif() find_package(Armadillo) set_package_properties(Armadillo PROPERTIES URL "http://arma.sourceforge.net/" - DESCRIPTION "C++ library for linear algebra and scientific computing" PURPOSE "Used for matrix computations." TYPE REQUIRED ) @@ -1445,6 +1465,7 @@ if(NOT ARMADILLO_FOUND OR ENABLE_OWN_ARMADILLO) INTERFACE_LINK_LIBRARIES "${binary_dir}/${CMAKE_FIND_LIBRARY_PREFIXES}armadillo${CMAKE_STATIC_LIBRARY_SUFFIX}" ) set_package_properties(Armadillo PROPERTIES + DESCRIPTION "C++ library for linear algebra and scientific computing" PURPOSE "Armadillo ${GNSSSDR_ARMADILLO_LOCAL_VERSION} will be downloaded and built when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'." ) endif() @@ -1503,7 +1524,7 @@ if(NOT GNUTLS_OPENSSL_LIBRARY) find_package(OpenSSL) set_package_properties(OpenSSL PROPERTIES URL "https://www.openssl.org" - DESCRIPTION "Cryptography and SSL/TLS Toolkit" + DESCRIPTION "Cryptography and SSL/TLS Toolkit (found: v${OPENSSL_VERSION})" PURPOSE "Used for the SUPL protocol implementation." TYPE REQUIRED ) @@ -1540,7 +1561,6 @@ endif() find_package(MATIO) set_package_properties(MATIO PROPERTIES URL "https://github.com/tbeu/matio" - DESCRIPTION "MATLAB MAT File I/O Library" PURPOSE "Used to store processing block's results in MAT files readable from MATLAB/Octave." TYPE REQUIRED ) @@ -1550,6 +1570,9 @@ if(NOT MATIO_FOUND OR MATIO_VERSION_STRING VERSION_LESS ${GNSSSDR_MATIO_MIN_VERS endif() message(STATUS " Matio v${GNSSSDR_MATIO_LOCAL_VERSION} will be downloaded and built automatically") message(STATUS " when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'.") + set_package_properties(MATIO PROPERTIES + DESCRIPTION "MATLAB MAT File I/O Library" + ) find_package(ZLIB) set_package_properties(ZLIB PROPERTIES URL "https://www.zlib.net/" @@ -1682,7 +1705,7 @@ if(NOT MATIO_FOUND OR MATIO_VERSION_STRING VERSION_LESS ${GNSSSDR_MATIO_MIN_VERS ) else() set_package_properties(MATIO PROPERTIES - DESCRIPTION "MATLAB MAT File I/O Library (found: v.${MATIO_VERSION_STRING})" + DESCRIPTION "MATLAB MAT File I/O Library (found: v${MATIO_VERSION_STRING})" ) endif() @@ -1694,11 +1717,13 @@ endif() find_package(PUGIXML) set_package_properties(PUGIXML PROPERTIES URL "https://pugixml.org/" - DESCRIPTION "Light-weight, simple and fast XML parser for C++" PURPOSE "Used to handle Galileo almanac XML files published by the European GNSS Service Centre." TYPE REQUIRED ) if(NOT PUGIXML_FOUND) + set_package_properties(PUGIXML PROPERTIES + DESCRIPTION "Light-weight, simple and fast XML parser for C++" + ) message(STATUS " PugiXML v${GNSSSDR_PUGIXML_LOCAL_VERSION} will be downloaded and built when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'.") set(PUGIXML_COMPILER -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}) set(TOOLCHAIN_ARG "") @@ -1748,6 +1773,16 @@ if(NOT PUGIXML_FOUND) set_package_properties(PUGIXML PROPERTIES PURPOSE "PugiXML v${GNSSSDR_PUGIXML_LOCAL_VERSION} will be downloaded and built when doing '${CMAKE_MAKE_PROGRAM_PRETTY_NAME}'." ) +else() + if(PUGIXML_VERSION) + set_package_properties(PUGIXML PROPERTIES + DESCRIPTION "Light-weight, simple and fast XML parser for C++ (found: ${PUGIXML_VERSION})" + ) + else() + set_package_properties(PUGIXML PROPERTIES + DESCRIPTION "Light-weight, simple and fast XML parser for C++" + ) + endif() endif() @@ -1758,7 +1793,6 @@ endif() find_package(Protobuf) set_package_properties(Protobuf PROPERTIES URL "https://developers.google.com/protocol-buffers/" - DESCRIPTION "Structured data serialization mechanism" PURPOSE "Used to serialize output data in a way that can be read by other applications." TYPE REQUIRED ) @@ -1816,6 +1850,10 @@ if(Protobuf_FOUND) set_package_properties(Protobuf PROPERTIES DESCRIPTION "Structured data serialization mechanism (found: v${Protobuf_VERSION})" ) +else() + set_package_properties(Protobuf PROPERTIES + DESCRIPTION "Structured data serialization mechanism" + ) endif() if(Protobuf_FOUND AND CMAKE_CROSSCOMPILING) @@ -2159,7 +2197,6 @@ endif() find_package(GROSMOSDR) set_package_properties(GROSMOSDR PROPERTIES URL "https://osmocom.org/projects/gr-osmosdr/wiki" - DESCRIPTION "osmocom GNU Radio blocks" PURPOSE "Used for communication with OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based dongles, etc.)." TYPE OPTIONAL ) @@ -2167,7 +2204,19 @@ if(ENABLE_OSMOSDR) if(GROSMOSDR_FOUND) message(STATUS "The driver for OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based dongles, etc.) will be compiled.") message(STATUS " You can disable it with 'cmake -DENABLE_OSMOSDR=OFF ..'") + if(GROSMOSDR_VERSION) + set_package_properties(GROSMOSDR PROPERTIES + DESCRIPTION "osmocom GNU Radio blocks (found: ${GROSMOSDR_VERSION})" + ) + else() + set_package_properties(GROSMOSDR PROPERTIES + DESCRIPTION "osmocom GNU Radio blocks" + ) + endif() else() + set_package_properties(GROSMOSDR PROPERTIES + DESCRIPTION "osmocom GNU Radio blocks" + ) if(ENABLE_PACKAGING) message(WARNING "gr-osmosdr has not been found. Source blocks depending on it will NOT be built.") else() @@ -2175,6 +2224,9 @@ if(ENABLE_OSMOSDR) endif() endif() else() + set_package_properties(GROSMOSDR PROPERTIES + DESCRIPTION "osmocom GNU Radio blocks" + ) message(STATUS "The (optional) driver for OsmoSDR and related front-ends is not enabled.") message(STATUS " Enable it with 'cmake -DENABLE_OSMOSDR=ON ..' to add support for OsmoSDR and other front-ends (HackRF, bladeRF, Realtek's RTL2832U-based USB dongles, etc.)") endif() @@ -2188,10 +2240,19 @@ endif() find_package(GRIIO) set_package_properties(GRIIO PROPERTIES URL "https://github.com/analogdevicesinc/gr-iio" - DESCRIPTION "IIO blocks for GNU Radio" PURPOSE "Used for communication with PlutoSDR and FMCOMMS devices." TYPE OPTIONAL ) +if(GRIIO_FOUND AND GRIIO_VERSION) + set_package_properties(GRIIO PROPERTIES + DESCRIPTION "IIO blocks for GNU Radio (found: v${GRIIO_VERSION})" + ) +else() + set_package_properties(GRIIO PROPERTIES + DESCRIPTION "IIO blocks for GNU Radio" + ) +endif() + ##################################################################### @@ -2202,10 +2263,18 @@ set_package_properties(GRIIO PROPERTIES find_package(LIBIIO) set_package_properties(LIBIIO PROPERTIES URL "https://github.com/analogdevicesinc/libiio" - DESCRIPTION "A library for interfacing with Linux IIO devices" PURPOSE "Used for communication with the AD9361 chipset." TYPE OPTIONAL ) +if(LIBIIO_FOUND AND LIBIIO_VERSION) + set_package_properties(LIBIIO PROPERTIES + DESCRIPTION "A library for interfacing with Linux IIO devices (found: v${LIBIIO_VERSION})" + ) +else() + set_package_properties(LIBIIO PROPERTIES + DESCRIPTION "A library for interfacing with Linux IIO devices" + ) +endif() ############################################## diff --git a/cmake/Modules/FindGRIIO.cmake b/cmake/Modules/FindGRIIO.cmake index 8b83d9386..720313b15 100644 --- a/cmake/Modules/FindGRIIO.cmake +++ b/cmake/Modules/FindGRIIO.cmake @@ -92,6 +92,10 @@ find_library(IIO_LIBRARIES include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GRIIO DEFAULT_MSG IIO_LIBRARIES IIO_INCLUDE_DIRS) +if(PC_IIO_VERSION) + set(GRIIO_VERSION ${PC_IIO_VERSION}) +endif() + if(GRIIO_FOUND AND NOT TARGET Gnuradio::iio) add_library(Gnuradio::iio SHARED IMPORTED) set_target_properties(Gnuradio::iio PROPERTIES diff --git a/cmake/Modules/FindGROSMOSDR.cmake b/cmake/Modules/FindGROSMOSDR.cmake index 0054db97d..e655a20d8 100644 --- a/cmake/Modules/FindGROSMOSDR.cmake +++ b/cmake/Modules/FindGROSMOSDR.cmake @@ -95,6 +95,10 @@ find_library(GROSMOSDR_LIBRARIES include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GROSMOSDR DEFAULT_MSG GROSMOSDR_LIBRARIES GROSMOSDR_INCLUDE_DIR) +if(GROSMOSDR_PKG_VERSION) + set(GROSMOSDR_VERSION ${GROSMOSDR_PKG_VERSION}) +endif() + if(GROSMOSDR_FOUND AND NOT TARGET Gnuradio::osmosdr) add_library(Gnuradio::osmosdr SHARED IMPORTED) set_target_properties(Gnuradio::osmosdr PROPERTIES diff --git a/cmake/Modules/FindLIBIIO.cmake b/cmake/Modules/FindLIBIIO.cmake index ccf9fd133..4c94bb9dd 100644 --- a/cmake/Modules/FindLIBIIO.cmake +++ b/cmake/Modules/FindLIBIIO.cmake @@ -85,6 +85,10 @@ endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LIBIIO DEFAULT_MSG LIBIIO_LIBRARIES LIBIIO_INCLUDE_DIRS) +if(PC_LIBIIO_VERSION) + set(LIBIIO_VERSION ${PC_LIBIIO_VERSION}) +endif() + if(LIBIIO_FOUND AND NOT TARGET Iio::iio) add_library(Iio::iio SHARED IMPORTED) set_target_properties(Iio::iio PROPERTIES diff --git a/cmake/Modules/FindLIBOSMOSDR.cmake b/cmake/Modules/FindLIBOSMOSDR.cmake index 7534f4a00..5db152d21 100644 --- a/cmake/Modules/FindLIBOSMOSDR.cmake +++ b/cmake/Modules/FindLIBOSMOSDR.cmake @@ -42,6 +42,7 @@ find_path(LIBOSMOSDR_INCLUDE_DIR NAMES osmosdr.h /usr/local/include ${LIBOSMOSDR_ROOT}/include $ENV{LIBOSMOSDR_ROOT}/include + ${LIBOSMOSDR_PKG_INCLUDEDIR} ) find_library(LIBOSMOSDR_LIBRARIES NAMES osmosdr @@ -77,6 +78,7 @@ find_library(LIBOSMOSDR_LIBRARIES NAMES osmosdr $ENV{LIBOSMOSDR_ROOT}/lib ${LIBOSMOSDR_ROOT}/lib64 $ENV{LIBOSMOSDR_ROOT}/lib64 + ${LIBOSMOSDR_PKG_LIBDIR} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/FindPUGIXML.cmake b/cmake/Modules/FindPUGIXML.cmake index 3d8ce2bdc..2868b63bd 100644 --- a/cmake/Modules/FindPUGIXML.cmake +++ b/cmake/Modules/FindPUGIXML.cmake @@ -27,6 +27,9 @@ # Pugixml::pugixml # +include(FindPkgConfig) +pkg_check_modules(PC_PUGIXML pugixml QUIET) + find_path(PUGIXML_INCLUDE_DIR NAMES pugixml.hpp PATHS ${PUGIXML_HOME}/include @@ -38,6 +41,7 @@ find_path(PUGIXML_INCLUDE_DIR $ENV{PUGIXML_ROOT}/include ${PUGIXML_ROOT}/include/pugixml-1.9 $ENV{PUGIXML_ROOT}/include/pugixml-1.9 + ${PC_PUGIXML_INCLUDEDIR} ) find_library(PUGIXML_LIBRARY @@ -67,6 +71,7 @@ find_library(PUGIXML_LIBRARY $ENV{PUGIXML_ROOT}/lib/pugixml-1.9 ${PUGIXML_ROOT}/lib64/pugixml-1.9 $ENV{PUGIXML_ROOT}/lib64/pugixml-1.9 + ${PC_PUGIXML_LIBDIR} ) # Support the REQUIRED and QUIET arguments, and set PUGIXML_FOUND if found. @@ -80,6 +85,9 @@ if(PUGIXML_FOUND) message(STATUS "PugiXML include = ${PUGIXML_INCLUDE_DIR}") message(STATUS "PugiXML library = ${PUGIXML_LIBRARY}") endif() + if(PC_PUGIXML_VERSION) + set(PUGIXML_VERSION ${PC_PUGIXML_VERSION}) + endif() else() message(STATUS "PugiXML not found.") endif() diff --git a/cmake/Modules/FindUHD.cmake b/cmake/Modules/FindUHD.cmake index e0d6d77e0..6b9c09b5a 100644 --- a/cmake/Modules/FindUHD.cmake +++ b/cmake/Modules/FindUHD.cmake @@ -77,6 +77,20 @@ find_library(UHD_LIBRARIES include(FindPackageHandleStandardArgs) find_package_handle_standard_args(UHD DEFAULT_MSG UHD_LIBRARIES UHD_INCLUDE_DIRS) +if(PC_UHD_VERSION) + set(UHD_VERSION ${PC_UHD_VERSION}) +endif() +if(NOT PC_UHD_VERSION) + list(GET UHD_LIBRARIES 0 FIRST_DIR) + get_filename_component(UHD_LIBRARIES_DIR ${FIRST_DIR} DIRECTORY) + if(EXISTS ${UHD_LIBRARIES_DIR}/cmake/uhd/UHDConfigVersion.cmake) + include(${UHD_LIBRARIES_DIR}/cmake/uhd/UHDConfigVersion.cmake) + endif() + if(PACKAGE_VERSION) + set(UHD_VERSION ${PACKAGE_VERSION}) + endif() +endif() + if(UHD_FOUND AND NOT TARGET Uhd::uhd) add_library(Uhd::uhd SHARED IMPORTED) set_target_properties(Uhd::uhd PROPERTIES diff --git a/cmake/Modules/FindVOLK.cmake b/cmake/Modules/FindVOLK.cmake index 26d236625..7f5497364 100644 --- a/cmake/Modules/FindVOLK.cmake +++ b/cmake/Modules/FindVOLK.cmake @@ -25,7 +25,7 @@ ######################################################################## include(FindPkgConfig) -pkg_check_modules(PC_VOLK volk) +pkg_check_modules(PC_VOLK volk QUIET) find_path(VOLK_INCLUDE_DIRS NAMES volk/volk.h @@ -78,6 +78,22 @@ find_library(VOLK_LIBRARIES include(FindPackageHandleStandardArgs) find_package_handle_standard_args(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) + +if(PC_VOLK_VERSION) + set(VOLK_VERSION ${PC_VOLK_VERSION}) +endif() + +if(NOT VOLK_VERSION) + list(GET VOLK_LIBRARIES 0 FIRST_DIR) + get_filename_component(VOLK_LIB_DIR ${FIRST_DIR} DIRECTORY) + if(EXISTS ${VOLK_LIB_DIR}/cmake/volk/VolkConfigVersion.cmake) + include(${VOLK_LIB_DIR}/cmake/volk/VolkConfigVersion.cmake) + endif() + if(PACKAGE_VERSION) + set(VOLK_VERSION ${PACKAGE_VERSION}) + endif() +endif() + mark_as_advanced(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_VERSION) if(VOLK_FOUND AND NOT TARGET Volk::volk) diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index ba3cd23b0..e9cba3c93 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -129,6 +129,7 @@ endif() set(SIGNAL_SOURCE_ADAPTER_SOURCES file_signal_source.cc + multichannel_file_signal_source.cc gen_signal_source.cc nsr_file_signal_source.cc spir_file_signal_source.cc @@ -142,6 +143,7 @@ set(SIGNAL_SOURCE_ADAPTER_SOURCES set(SIGNAL_SOURCE_ADAPTER_HEADERS file_signal_source.h + multichannel_file_signal_source.h gen_signal_source.h nsr_file_signal_source.h spir_file_signal_source.h diff --git a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc new file mode 100644 index 000000000..11efe4fd9 --- /dev/null +++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.cc @@ -0,0 +1,311 @@ +/*! + * \file multichannel_file_signal_source.cc + * \brief Implementation of a class that reads signals samples from files at + * different frequency band and adapts it to a SignalSourceInterface + * \author Javier Arribas, 2019 jarribas(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "multichannel_file_signal_source.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_valve.h" +#include +#include +#include +#include +#include // for std::cerr +#include + + +MultichannelFileSignalSource::MultichannelFileSignalSource(ConfigurationInterface* configuration, + const std::string& role, unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue) : role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(std::move(queue)) +{ + std::string default_filename = "./example_capture.dat"; + std::string default_item_type = "short"; + std::string default_dump_filename = "./my_capture.dat"; + + double default_seconds_to_skip = 0.0; + size_t header_size = 0; + samples_ = configuration->property(role + ".samples", 0); + sampling_frequency_ = configuration->property(role + ".sampling_frequency", 0); + n_channels_ = configuration->property(role + ".total_channels", 1); + + for (unsigned int n = 0; n < n_channels_; n++) + { + filename_vec_.push_back(configuration->property(role + ".filename" + std::to_string(n), default_filename)); + } + + item_type_ = configuration->property(role + ".item_type", default_item_type); + repeat_ = configuration->property(role + ".repeat", false); + enable_throttle_control_ = configuration->property(role + ".enable_throttle_control", false); + + double seconds_to_skip = configuration->property(role + ".seconds_to_skip", default_seconds_to_skip); + header_size = configuration->property(role + ".header_size", 0); + int64_t samples_to_skip = 0; + + bool is_complex = false; + + if (item_type_ == "gr_complex") + { + item_size_ = sizeof(gr_complex); + } + else if (item_type_ == "float") + { + item_size_ = sizeof(float); + } + else if (item_type_ == "short") + { + item_size_ = sizeof(int16_t); + } + else if (item_type_ == "ishort") + { + item_size_ = sizeof(int16_t); + is_complex = true; + } + else if (item_type_ == "byte") + { + item_size_ = sizeof(int8_t); + } + else if (item_type_ == "ibyte") + { + item_size_ = sizeof(int8_t); + is_complex = true; + } + else + { + LOG(WARNING) << item_type_ + << " unrecognized item type. Using gr_complex."; + item_size_ = sizeof(gr_complex); + } + try + { + for (unsigned int n = 0; n < n_channels_; n++) + { + file_source_vec_.push_back(gr::blocks::file_source::make(item_size_, filename_vec_.at(n).c_str(), repeat_)); + + if (seconds_to_skip > 0) + { + samples_to_skip = static_cast(seconds_to_skip * sampling_frequency_); + + if (is_complex) + { + samples_to_skip *= 2; + } + } + if (header_size > 0) + { + samples_to_skip += header_size; + } + + if (samples_to_skip > 0) + { + LOG(INFO) << "Skipping " << samples_to_skip << " samples of the input file #" << n; + if (not file_source_vec_.back()->seek(samples_to_skip, SEEK_SET)) + { + LOG(INFO) << "Error skipping bytes!"; + } + } + } + } + catch (const std::exception& e) + { + if (filename_vec_.at(0) == default_filename) + { + std::cerr + << "The configuration file has not been found." + << std::endl + << "Please create a configuration file based on the examples at the 'conf/' folder " + << std::endl + << "and then generate your own GNSS Software Defined Receiver by doing:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl; + } + else + { + std::cerr + << "The receiver was configured to work with a file signal source " + << std::endl + << "but the specified file is unreachable by GNSS-SDR." + << std::endl + << "Please modify your configuration file" + << std::endl + << "and point SignalSource.filename to a valid raw data file. Then:" + << std::endl + << "$ gnss-sdr --config_file=/path/to/my_GNSS_SDR_configuration.conf" + << std::endl + << "Examples of configuration files available at:" + << std::endl + << GNSSSDR_INSTALL_DIR "/share/gnss-sdr/conf/" + << std::endl; + } + + LOG(INFO) << "file_signal_source: Unable to open the samples file " + << filename_vec_.at(0).c_str() << ", exiting the program."; + throw(e); + } + + //todo from here.... add mux demux also + if (samples_ == 0) // read all file + { + /*! + * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. + * A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the + * valve block + */ + std::ifstream file(filename_vec_.at(0).c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size())); + } + else + { + std::cout << "file_signal_source: Unable to open the samples file " << filename_vec_.at(0).c_str() << std::endl; + LOG(ERROR) << "file_signal_source: Unable to open the samples file " << filename_vec_.at(0).c_str(); + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename_vec_.at(0) << ", which contains " << static_cast(size) << " [bytes]" << std::endl; + std::cout.precision(ss); + + if (size > 0) + { + int64_t bytes_to_skip = samples_to_skip * item_size_; + int64_t bytes_to_process = static_cast(size) - bytes_to_skip; + samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size()) - ceil(0.002 * static_cast(sampling_frequency_))); // process all the samples available in the file excluding at least the last 1 ms + } + } + + CHECK(samples_ > 0) << "File does not contain enough samples to process."; + double signal_duration_s; + signal_duration_s = static_cast(samples_) * (1 / static_cast(sampling_frequency_)); + + if (is_complex) + { + signal_duration_s /= 2.0; + } + + DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; + std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]" << std::endl; + + valve_ = gnss_sdr_make_valve(item_size_, samples_, queue_); + DLOG(INFO) << "valve(" << valve_->unique_id() << ")"; + + if (enable_throttle_control_) + { + for (unsigned int n = 0; n < n_channels_; n++) + { + throttle_vec_.push_back(gr::blocks::throttle::make(item_size_, sampling_frequency_)); + } + } + + for (unsigned int n = 0; n < n_channels_; n++) + { + LOG(INFO) << "Multichanne File source filename #" << n << filename_vec_.at(n); + } + + DLOG(INFO) << "Samples " << samples_; + DLOG(INFO) << "Sampling frequency " << sampling_frequency_; + DLOG(INFO) << "Item type " << item_type_; + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "Repeat " << repeat_; + + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +MultichannelFileSignalSource::~MultichannelFileSignalSource() = default; + + +void MultichannelFileSignalSource::connect(gr::top_block_sptr top_block) +{ + if (enable_throttle_control_ == true) + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->connect(file_source_vec_.at(n), 0, throttle_vec_.at(n), 0); + DLOG(INFO) << "connected file_source #" << n << " to throttle"; + top_block->connect(throttle_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "connected throttle #" << n << " to valve_"; + } + } + else + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->connect(file_source_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "connected file_source #" << n << " to valve_"; + } + } +} + + +void MultichannelFileSignalSource::disconnect(gr::top_block_sptr top_block) +{ + if (enable_throttle_control_ == true) + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->disconnect(file_source_vec_.at(n), 0, throttle_vec_.at(n), 0); + DLOG(INFO) << "disconnected file_source #" << n << " to throttle"; + top_block->disconnect(throttle_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "disconnected throttle #" << n << " to valve_"; + } + } + else + { + for (unsigned int n = 0; n < n_channels_; n++) + { + top_block->disconnect(file_source_vec_.at(n), 0, valve_, n); + DLOG(INFO) << "disconnected file_source #" << n << " to valve_"; + } + } +} + + +gr::basic_block_sptr MultichannelFileSignalSource::get_left_block() +{ + LOG(WARNING) << "Left block of a signal source should not be retrieved"; + return gr::blocks::file_source::sptr(); +} + + +gr::basic_block_sptr MultichannelFileSignalSource::get_right_block() +{ + return valve_; +} diff --git a/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h new file mode 100644 index 000000000..b248073dd --- /dev/null +++ b/src/algorithms/signal_source/adapters/multichannel_file_signal_source.h @@ -0,0 +1,131 @@ +/*! + * \file multichannel_file_signal_source.h + * \brief Implementation of a class that reads signals samples from files at + * different frequency band and adapts it to a SignalSourceInterface + * \author Javier Arribas, 2019 jarribas(at)cttc.es + * + * This class represents a file signal source. Internally it uses a GNU Radio's + * gr_file_source as a connector to the data. + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR 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 GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ +#define GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ + +#include "gnss_block_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class ConfigurationInterface; + +/*! + * \brief Class that reads signals samples from files at different frequency bands + * and adapts it to a SignalSourceInterface + */ +class MultichannelFileSignalSource : public GNSSBlockInterface +{ +public: + MultichannelFileSignalSource(ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + boost::shared_ptr queue); + + virtual ~MultichannelFileSignalSource(); + + inline std::string role() override + { + return role_; + } + + /*! + * \brief Returns "Multichannel_File_Signal_Source". + */ + inline std::string implementation() override + { + return "Multichannel_File_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; + + inline std::string filename() const + { + return filename_vec_.at(0); + } + + inline std::string item_type() const + { + return item_type_; + } + + inline bool repeat() const + { + return repeat_; + } + + inline int64_t sampling_frequency() const + { + return sampling_frequency_; + } + + inline uint64_t samples() const + { + return samples_; + } + +private: + uint64_t samples_; + int64_t sampling_frequency_; + uint32_t n_channels_; + std::vector filename_vec_; + std::string item_type_; + bool repeat_; + std::string role_; + uint32_t in_streams_; + uint32_t out_streams_; + std::vector file_source_vec_; + boost::shared_ptr valve_; + gr::blocks::file_sink::sptr sink_; + std::vector throttle_vec_; + boost::shared_ptr queue_; + size_t item_size_; + // Throttle control + bool enable_throttle_control_; +}; + +#endif /* GNSS_SDR_MULTICHANNEL_FILE_SIGNAL_SOURCE_H_ */ diff --git a/src/algorithms/signal_source/libs/gnss_sdr_valve.cc b/src/algorithms/signal_source/libs/gnss_sdr_valve.cc index 19626a5d4..aa2bd1237 100644 --- a/src/algorithms/signal_source/libs/gnss_sdr_valve.cc +++ b/src/algorithms/signal_source/libs/gnss_sdr_valve.cc @@ -44,8 +44,8 @@ Gnss_Sdr_Valve::Gnss_Sdr_Valve(size_t sizeof_stream_item, uint64_t nitems, gr::msg_queue::sptr queue, bool stop_flowgraph) : gr::sync_block("valve", - gr::io_signature::make(1, 1, sizeof_stream_item), - gr::io_signature::make(1, 1, sizeof_stream_item)), + gr::io_signature::make(1, 20, sizeof_stream_item), + gr::io_signature::make(1, 20, sizeof_stream_item)), d_nitems(nitems), d_ncopied_items(0), d_queue(std::move(queue)), @@ -99,11 +99,17 @@ int Gnss_Sdr_Valve::work(int noutput_items, { return 0; } - memcpy(output_items[0], input_items[0], n * input_signature()->sizeof_stream_item(0)); + // multichannel support + for (unsigned int ch = 0; ch < output_items.size(); ch++) + { + memcpy(output_items[ch], input_items[ch], n * input_signature()->sizeof_stream_item(ch)); + } d_ncopied_items += n; return n; } - - memcpy(output_items[0], input_items[0], noutput_items * input_signature()->sizeof_stream_item(0)); + for (unsigned int ch = 0; ch < output_items.size(); ch++) + { + memcpy(output_items[ch], input_items[ch], noutput_items * input_signature()->sizeof_stream_item(ch)); + } return noutput_items; } diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index b4ede27ac..7976d99da 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -97,6 +97,7 @@ #include "ishort_to_cshort.h" #include "labsat_signal_source.h" #include "mmse_resampler_conditioner.h" +#include "multichannel_file_signal_source.h" #include "notch_filter.h" #include "notch_filter_lite.h" #include "nsr_file_signal_source.h" @@ -1261,6 +1262,21 @@ std::unique_ptr GNSSBlockFactory::GetBlock( block = std::move(block_); } + catch (const std::exception& e) + { + std::cout << "GNSS-SDR program ended." << std::endl; + exit(1); + } + } + else if (implementation == "Multichannel_File_Signal_Source") + { + try + { + std::unique_ptr block_(new MultichannelFileSignalSource(configuration.get(), role, in_streams, + out_streams, queue)); + block = std::move(block_); + } + catch (const std::exception& e) { std::cout << "GNSS-SDR program ended." << std::endl; diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 4282d26ee..0611a4e26 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -215,10 +215,10 @@ void GNSSFlowgraph::connect() } DLOG(INFO) << "blocks connected internally"; - // Signal Source (i) > Signal conditioner (i) > +// Signal Source (i) > Signal conditioner (i) > #ifndef ENABLE_FPGA int RF_Channels = 0; - int signal_conditioner_ID = 0; + unsigned int signal_conditioner_ID = 0; for (int i = 0; i < sources_count_; i++) { try @@ -249,10 +249,13 @@ void GNSSFlowgraph::connect() DLOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); DLOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) { - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + if (sig_conditioner_.size() > signal_conditioner_ID) + { + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } } else { @@ -819,7 +822,7 @@ void GNSSFlowgraph::disconnect() for (int j = 0; j < RF_Channels; j++) { - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1 or sig_source_.at(i)->get_right_block()->output_signature()->max_streams() == -1) { top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); }