diff options
102 files changed, 5451 insertions, 4041 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05e004f --- /dev/null +++ b/.gitignore @@ -0,0 +1,74 @@ +*~ +*.pyc +*.pyo +build*/ +cmake-* +libosmo-dsp/* + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser diff --git a/CMakeLists.txt b/CMakeLists.txt index 74c54f5..76375dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,12 +21,20 @@ # Project setup ######################################################################## cmake_minimum_required(VERSION 3.8) -include(GNUInstallDirs) project(gr-osmosdr CXX C) enable_testing() -#policy setup -cmake_policy(SET CMP0011 NEW) +#install to PyBOMBS target prefix if defined +if(DEFINED ENV{PYBOMBS_PREFIX}) + set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX}) + message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}") +endif() + +# Get GNU Radio Installation Prefix +if(DEFINED CMAKE_INSTALL_PREFIX) + set(GR_PREFIX ${CMAKE_INSTALL_PREFIX}) + message(STATUS "Installation is located at: ${GR_PREFIX}") +endif() #select the release build type by default to get optimization flags if(NOT CMAKE_BUILD_TYPE) @@ -35,190 +43,104 @@ if(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") -######################################################################## -# GNURadio setup -######################################################################## +#make sure our local CMake Modules path comes first list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) -# Find GNURadio (pmt and runtime are core, always included) -find_package(Gnuradio "3.8" REQUIRED COMPONENTS blocks fft filter) +set(ENABLE_NONFREE FALSE CACHE BOOL "Enable or disable nonfree components.") # Set the version information here -set(VERSION_MAJOR 0) -set(VERSION_API 2) -set(VERSION_ABI 0) -set(VERSION_PATCH 0) -include(GrVersion) #setup version info +set(VERSION_INFO_MAJOR_VERSION 0) +set(VERSION_INFO_API_COMPAT 1) +set(VERSION_INFO_MINOR_VERSION 5) +set(VERSION_INFO_MAINT_VERSION git) + +cmake_policy(SET CMP0011 NEW) + ######################################################################## # Compiler specific setup ######################################################################## - -if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR - CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - AND NOT WIN32) - #http://gcc.gnu.org/wiki/Visibility - add_definitions(-fvisibility=hidden) - add_definitions(-fvisibility-inlines-hidden) -endif() - -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_STANDARD 11) -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_STANDARD 11) -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set(CMAKE_CXX_STANDARD 11) -else() - message(WARNING "C++ standard could not be set because compiler is not GNU, Clang or MSVC.") -endif() - -# Misc options -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR - CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - add_definitions(-Wall) - add_definitions(-Wextra) - add_definitions(-Wno-unused-parameter) - add_definitions(-Wsign-compare) - #add_definitions(-Wconversion) - #add_definitions(-pedantic) - #add_definitions(-ansi) -endif() - -# SIMD -if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|x86") - set(USE_SIMD "SSE2" CACHE STRING "Use SIMD instructions") -else() - set(USE_SIMD "no" CACHE STRING "Use SIMD instructions") -endif() -set(USE_SIMD_VALUES "no" "SSE2" "AVX") -set_property(CACHE USE_SIMD PROPERTY STRINGS ${USE_SIMD_VALUES}) -list(FIND USE_SIMD_VALUES ${USE_SIMD} USE_SIMD_INDEX) -if(${USE_SIMD_INDEX} EQUAL -1) +IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|x86") + SET(USE_SIMD "SSE2" CACHE STRING "Use SIMD instructions") +ELSE() + SET(USE_SIMD "no" CACHE STRING "Use SIMD instructions") +ENDIF() +SET(USE_SIMD_VALUES "no" "SSE2" "AVX") +SET_PROPERTY(CACHE USE_SIMD PROPERTY STRINGS ${USE_SIMD_VALUES}) +LIST(FIND USE_SIMD_VALUES ${USE_SIMD} USE_SIMD_INDEX) +IF(${USE_SIMD_INDEX} EQUAL -1) message(FATAL_ERROR "Option ${USE_SIMD} not supported, valid entries are ${USE_SIMD_VALUES}") -endif() +ENDIF() + +IF(CMAKE_CXX_COMPILER MATCHES ".*clang") + SET(CMAKE_COMPILER_IS_CLANGXX 1) +ENDIF() + +IF(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) + ADD_DEFINITIONS(-Wall) + ADD_DEFINITIONS(-Wextra) + ADD_DEFINITIONS(-Wno-unused-parameter) + ADD_DEFINITIONS(-Wsign-compare) + #ADD_DEFINITIONS(-Wconversion) + #ADD_DEFINITIONS(-pedantic) + #ADD_DEFINITIONS(-ansi) + IF(NOT WIN32) + #only export symbols that are declared to be part of the api (non dll platforms) + ADD_DEFINITIONS(-fvisibility=hidden) + ADD_DEFINITIONS(-fvisibility-inlines-hidden) + ENDIF(NOT WIN32) + IF(USE_SIMD MATCHES SSE2) + ADD_DEFINITIONS(-msse2) + ADD_DEFINITIONS(-DUSE_SSE2) + ENDIF() + IF(USE_SIMD MATCHES AVX) + ADD_DEFINITIONS(-march=native) + ADD_DEFINITIONS(-DUSE_AVX) + ENDIF() +ELSEIF(MSVC) + IF(USE_SIMD MATCHES SSE2) + ADD_DEFINITIONS(/arch:SSE2) + ADD_DEFINITIONS(-DUSE_SSE2) + ENDIF() + IF(USE_SIMD MATCHES AVX) + ADD_DEFINITIONS(/arch:AVX) + ADD_DEFINITIONS(-DUSE_AVX) + ENDIF() +ENDIF() -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR - CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(USE_SIMD MATCHES SSE2) - add_definitions(-msse2) - add_definitions(-DUSE_SSE2) - endif() - if(USE_SIMD MATCHES AVX) - add_definitions(-march=native) - add_definitions(-DUSE_AVX) - endif() -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - if(USE_SIMD MATCHES SSE2) - add_definitions(/arch:SSE2) - add_definitions(-DUSE_SSE2) - endif() - if(USE_SIMD MATCHES AVX) - add_definitions(/arch:AVX) - add_definitions(-DUSE_AVX) - endif() - # boost feels like using lib pragmas to link to libs, - # but the boost libs might not even be in the (default) lib search path - add_definitions(-DBOOST_ALL_NO_LIB) - # macro turns std::min into errors... - add_definitions(-DNOMINMAX) -endif() ######################################################################## -# Find boost +# Install directories ######################################################################## -find_package(Boost "1.65" REQUIRED chrono thread system) - -if(NOT Boost_FOUND) - message(FATAL_ERROR "Boost required to compile osmosdr") +find_package(Gnuradio REQUIRED) # Side effect of MODULE_PATH getting prepended with system components +list(REVERSE CMAKE_MODULE_PATH) +set(MIN_GR_VERSION "3.8") +if("${Gnuradio_VERSION}" VERSION_LESS MIN_GR_VERSION) + MESSAGE(FATAL_ERROR "GnuRadio version required: >=\"" ${MIN_GR_VERSION} "\" found: \"" ${Gnuradio_VERSION} "\"") endif() -######################################################################## -# Find build dependencies and setup options -######################################################################## - -include(GrComponent) - -set(ENABLE_NONFREE FALSE CACHE BOOL "Enable or disable nonfree components.") - +include(GrVersion) - # GNURadio components & OOTs - ############################## - - - # Note this is not supposed to be lique that for GR components - # but ATM GR's handling of components is broken -message(STATUS "Searching for GNURadio-Blocks...") -find_package(gnuradio-blocks PATHS ${Gnuradio_DIR}) -message(STATUS " Found GNURadio-Blocks: ${gnuradio-blocks_FOUND}") - -message(STATUS "Searching for IQ Balance...") -find_package(gnuradio-iqbalance PATHS ${Gnuradio_DIR}) -message (STATUS " Found IQ Balance: ${gnuradio-iqbalance_FOUND}") - -message(STATUS "Searching for UHD Drivers...") -find_package(UHD) -message (STATUS " Found UHD Driver: ${UHD_FOUND}") - -message(STATUS "Searching for UHD Block...") -find_package(gnuradio-uhd PATHS ${Gnuradio_DIR}) -message (STATUS " Found UHD Block: ${gnuradio-uhd_FOUND}") - -message(STATUS "Searching for Volk...") -find_package(Volk REQUIRED) -message (STATUS " Found Volk: ${Volk_FOUND}") - - # Hardware drivers - #################### - -find_package(LibRTLSDR) -if(ENABLE_NONFREE) - find_package(LibSDRplay) -endif(ENABLE_NONFREE) -find_package(LibHackRF) -find_package(LibAIRSPY) -find_package(LibAIRSPYHF) -find_package(LibbladeRF) -find_package(GnuradioFCDPP) -find_package(SoapySDR NO_MODULE) -find_package(LibFreeSRP) -find_package(LibXTRX) -find_package(Doxygen) - - # Python - ########## - -find_package(PythonLibs 3) -find_package(SWIG) - -if(SWIG_FOUND) - message(STATUS "Minimum SWIG version required is 1.3.31") - set(SWIG_VERSION_CHECK FALSE) - if("${SWIG_VERSION}" VERSION_GREATER "1.3.30") - set(SWIG_VERSION_CHECK TRUE) - endif() -endif(SWIG_FOUND) - -GR_REGISTER_COMPONENT("Python support" ENABLE_PYTHON - PYTHONLIBS_FOUND - SWIG_FOUND - SWIG_VERSION_CHECK -) - -######################################################################## -# Install directories -######################################################################## include(GrPlatform) #define LIB_SUFFIX - if(NOT CMAKE_MODULES_DIR) set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) endif(NOT CMAKE_MODULES_DIR) -set(GR_INCLUDE_DIR include) set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/osmosdr) +set(GR_RUNTIME_DIR bin) +set(GR_LIBRARY_DIR lib${LIB_SUFFIX}) +set(GR_INCLUDE_DIR include) +set(GR_DATA_DIR share) set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) -set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) +set(GR_DOC_DIR ${GR_DATA_DIR}/doc) +if (NOT GR_PKG_DOC_DIR) + set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) +endif() +set(GR_CONF_DIR etc) set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) +set(GR_LIBEXEC_DIR libexec) set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) +set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks) ######################################################################## # On Apple only, set install name and use rpath correctly, if not already set @@ -241,10 +163,67 @@ if(APPLE) endif(APPLE) ######################################################################## -# Setup doxygen option +# Find build dependencies ######################################################################## +set(GR_REQUIRED_COMPONENTS RUNTIME PMT BLOCKS) + +find_package(gnuradio-blocks PATHS ${GR_PREFIX}/lib/cmake/gnuradio/) +message(STATUS "Found Block Block: ${gnuradio-blocks_FOUND}") + +#[[find_package(gnuradio-pmt PATHS ${GR_PREFIX}/lib/cmake/gnuradio/) +message(STATUS "Found PMT Block: ${gnuradio-pmt_FOUND}") + +find_package(gnuradio-runtime PATHS ${GR_PREFIX}/lib/cmake/gnuradio/) +message(STATUS "Found Runtime Block: ${gnuradio-runtime_FOUND}") + +# Software Components part of GNU Radio - These should all be present for a default install +message(STATUS " Searching for IQ Balance...") +#find_package(Gnuradio COMPONENTS iqbalance REQUIRED) +find_package(gnuradio-iqbalance PATHS ${GR_PREFIX}/lib/cmake/iqbalance) +message (STATUS "Found IQ Balance: ${gnuradio-iqbalance_FOUND}") + +message(STATUS " Searching for UHD Drivers...") +#find_package(Gnuradio COMPONENTS uhd REQUIRED) +find_package(UHD REQUIRED ${GR_PREFIX}/lib/cmake/uhd) +message (STATUS "Found UHD Driver: ${UHD_FOUND}") + +message(STATUS " Searching for UHD Block...") +#find_package(Gnuradio COMPONENTS gnuradio-uhd REQUIRED) +find_package(gnuradio-uhd PATHS ${GR_PREFIX}/lib/cmake/gnuradio/) +message (STATUS "Found UHD Block: ${gnuradio-uhd_FOUND}") + +message(STATUS " Searching for Volk...") +#find_package(Gnuradio COMPONENTS Volk REQUIRED) +find_package(volk PATHS ${GR_PREFIX}/lib/cmake/volk) +message (STATUS "Found Volk: ${volk_FOUND}") ]]# + +find_package(GnuradioIQBalance) +find_package(UHD) +find_package(GnuradioUHD) +find_package(LibOsmoSDR) +find_package(LibRTLSDR) +find_package(LibMiriSDR) +if(ENABLE_NONFREE) + find_package(LibSDRplay) +endif(ENABLE_NONFREE) +find_package(LibHackRF) +find_package(LibAIRSPY) +find_package(Volk) +find_package(LibbladeRF) +find_package(SoapySDR NO_MODULE) +find_package(LibFreeSRP) find_package(Doxygen) +#get_cmake_property(_variableNames VARIABLES) +#list (SORT _variableNames) +#foreach (_variableName ${_variableNames}) +# message(STATUS "${_variableName}=${${_variableName}}") +#endforeach() + + +######################################################################## +# Setup doxygen option +######################################################################## if(DOXYGEN_FOUND) option(ENABLE_DOXYGEN "Build docs using Doxygen" ON) else(DOXYGEN_FOUND) @@ -252,6 +231,25 @@ else(DOXYGEN_FOUND) endif(DOXYGEN_FOUND) ######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories( + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/lib + ${Boost_INCLUDE_DIRS} + ${GNURADIO_ALL_INCLUDE_DIRS} +) + +link_directories( + ${Boost_LIBRARY_DIRS} + ${GNURADIO_ALL_LIBRARY_DIRS} +) + +# Set component parameters +set(GR_OSMOSDR_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE) +set(GR_OSMOSDR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE) + +######################################################################## # Create uninstall target ######################################################################## configure_file( @@ -263,6 +261,29 @@ add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) + +######################################################################## +# Enable python component +######################################################################## +find_package(PythonLibs) +find_package(SWIG) + +if(SWIG_FOUND) + message(STATUS "Minimum SWIG version required is 1.3.31") + set(SWIG_VERSION_CHECK FALSE) + if("${SWIG_VERSION}" VERSION_GREATER "1.3.30") + set(SWIG_VERSION_CHECK TRUE) + endif() +endif(SWIG_FOUND) + +include(GrComponent) +GR_REGISTER_COMPONENT("Python support" ENABLE_PYTHON + PYTHONLIBS_FOUND + SWIG_FOUND + SWIG_VERSION_CHECK + ) + + ######################################################################## # Add subdirectories ######################################################################## @@ -277,6 +298,51 @@ endif(ENABLE_PYTHON) add_subdirectory(docs) ######################################################################## +# Install cmake search helper for this library +######################################################################## + +install(FILES cmake/Modules/osmosdrConfig.cmake + DESTINATION ${CMAKE_MODULES_DIR}/osmosdr +) + +######################################################################## +# Create Pkg Config File +######################################################################## +FOREACH(inc ${Boost_INCLUDE_DIRS}) + LIST(APPEND GR_OSMOSDR_PC_CFLAGS "-I${inc}") +ENDFOREACH(inc) + +FOREACH(lib ${Boost_LIBRARY_DIRS}) + LIST(APPEND GR_OSMOSDR_PC_LIBS "-L${lib}") +ENDFOREACH(lib) + +# use space-separation format for the pc file +STRING(REPLACE ";" " " GR_OSMOSDR_PC_REQUIRES "${GR_OSMOSDR_PC_REQUIRES}") +STRING(REPLACE ";" " " GR_OSMOSDR_PC_CFLAGS "${GR_OSMOSDR_PC_CFLAGS}") +STRING(REPLACE ";" " " GR_OSMOSDR_PC_LIBS "${GR_OSMOSDR_PC_LIBS}") + +# unset these vars to avoid hard-coded paths to cross environment +IF(CMAKE_CROSSCOMPILING) + UNSET(GR_OSMOSDR_PC_CFLAGS) + UNSET(GR_OSMOSDR_PC_LIBS) +ENDIF(CMAKE_CROSSCOMPILING) + +# fake gnuradio cpack behavior as long as we don't use it directly +set(CPACK_PACKAGE_NAME "gnuradio-osmosdr") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GNU Radio block for various radio hardware") +set(CPACK_PACKAGE_VERSION ${VERSION}) + +CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/gnuradio-osmosdr.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-osmosdr.pc + @ONLY) + +INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-osmosdr.pc + DESTINATION ${GR_LIBRARY_DIR}/pkgconfig +) + +######################################################################## # Print Summary ######################################################################## GR_PRINT_COMPONENT_SUMMARY() @@ -284,7 +350,8 @@ if(ENABLE_NONFREE) MESSAGE(STATUS "NONFREE components have been enabled. The resulting binaries cannot be distributed under GPL terms. - ") + " + ) endif(ENABLE_NONFREE) MESSAGE(STATUS "Building for version: ${VERSION} / ${LIBVER}") @@ -1,10 +1,10 @@ While primarily being developed for the OsmoSDR hardware, this block as well supports: - * FUNcube Dongle through libgnuradio-fcd - * FUNcube Dongle Pro+ through gr-fcdproplus + * sysmocom OsmoSDR Devices through libosmosdr * RTL2832U based DVB-T dongles through librtlsdr * RTL-TCP spectrum server (see librtlsdr project) + * MSi2500 based DVB-T dongles through libmirisdr * SDRplay RSP through SDRplay API library * gnuradio .cfile input through libgnuradio-blocks * RFSPACE SDR-IQ, SDR-IP, NetSDR (incl. X2 option) @@ -13,8 +13,7 @@ as well supports: * Great Scott Gadgets HackRF through libhackrf * Nuand LLC bladeRF through libbladeRF library * Ettus USRP Devices through Ettus UHD library - * Fairwaves UmTRX through Fairwaves' module for UHD - * Fairwaves XTRX through libxtrx + * Fairwaves UmTRX through Fairwaves' fork of UHD * Red Pitaya SDR transceiver (http://bazaar.redpitaya.com) * FreeSRP through libfreesrp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 2b9e0c9..9c30a4b 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -28,7 +28,7 @@ GR_PYTHON_INSTALL( GR_PYTHON_INSTALL( PROGRAMS osmocom_fft - # osmocom_siggen + osmocom_siggen osmocom_siggen_nogui osmocom_spectrum_sense DESTINATION ${GR_RUNTIME_DIR} diff --git a/apps/osmocom_fft b/apps/osmocom_fft index 10a682c..da38861 100755 --- a/apps/osmocom_fft +++ b/apps/osmocom_fft @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # Copyright 2012 Free Software Foundation, Inc. # @@ -20,71 +20,45 @@ # Boston, MA 02110-1301, USA. # +SAMP_RANGE_KEY = 'samp_range' +SAMP_RATE_KEY = 'samp_rate' +GAIN_KEY = lambda x: 'gain:'+x +BWIDTH_KEY = 'bwidth' +CENTER_FREQ_KEY = 'center_freq' +FREQ_CORR_KEY = 'freq_corr' +FREQ_RANGE_KEY = 'freq_range' +GAIN_RANGE_KEY = lambda x: 'gain_range:'+x +BWIDTH_RANGE_KEY = 'bwidth_range' + import osmosdr from gnuradio import blocks -from gnuradio import gr +from gnuradio import gr, gru from gnuradio import eng_notation -from gnuradio.filter import firdes +from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option from optparse import OptionParser -from functools import partial import sys -import signal +import numpy import time import datetime try: - from PyQt5 import Qt - from gnuradio import qtgui - import sip - from gnuradio.qtgui import Range, RangeWidget + from gnuradio.wxgui import stdgui2, form, slider + from gnuradio.wxgui import forms + from gnuradio.wxgui import fftsink2, waterfallsink2, scopesink2 + import wx except ImportError: - sys.stderr.write("Error importing GNU Radio's Qtgui.\n") + sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n") sys.exit(1) +class app_top_block(stdgui2.std_top_block, pubsub): + def __init__(self, frame, panel, vbox, argv): + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) + pubsub.__init__(self) -class CallEvent(Qt.QEvent): - """An event containing a request for a function call.""" - EVENT_TYPE = Qt.QEvent.Type(Qt.QEvent.registerEventType()) - - def __init__(self, fn, *args, **kwargs): - Qt.QEvent.__init__(self, self.EVENT_TYPE) - self.fn = fn - self.args = args - self.kwargs = kwargs - - -class freq_recv(gr.sync_block, Qt.QObject): - def __init__(self, callback): - gr.sync_block.__init__(self, name="freq_recv", in_sig=None, out_sig=None) - Qt.QObject.__init__(self) - - self.set_freq=callback - - # Advertise 'msg' port - self.message_port_register_in(gr.pmt.intern('msg')) - self.set_msg_handler(gr.pmt.intern('msg'), self.handle_msg) - - def handle_msg(self, msg_pmt): - # Unpack message & call set_freq on main thread - meta = gr.pmt.to_python(gr.pmt.car(msg_pmt)) - msg = gr.pmt.cdr(msg_pmt) - if meta=="freq": - freq = gr.pmt.to_double(msg) - Qt.QCoreApplication.postEvent(self, CallEvent(self.set_freq, freq)) - - def event(self, event): - event.accept() - result = event.fn(*event.args, **event.kwargs) - return True - - -class app_top_block(gr.top_block, Qt.QMainWindow): - def __init__(self, argv, title): - gr.top_block.__init__(self, title) - Qt.QMainWindow.__init__(self) - self.setWindowTitle(title) + self.frame = frame + self.panel = panel parser = OptionParser(option_class=eng_option) parser.add_option("-a", "--args", type="string", default="", @@ -115,8 +89,6 @@ class app_top_block(gr.top_block, Qt.QMainWindow): help="Enable fosphor display") parser.add_option("-S", "--oscilloscope", action="store_true", default=False, help="Enable oscilloscope display") - parser.add_option("-Q", "--qtgui", action="store_true", default=False, - help="Enable QTgui 'all-in-one' display") parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, help="Set fftsink averaging factor, default=[%default]") parser.add_option("", "--averaging", action="store_true", default=False, @@ -140,20 +112,16 @@ class app_top_block(gr.top_block, Qt.QMainWindow): self._verbose = options.verbose - try: - self.src = osmosdr.source(options.args) - except RuntimeError: - print("Couldn't instanciate source (no device present?).", file=sys.stderr) - sys.exit(1) + self.src = osmosdr.source(options.args) try: self.src.get_sample_rates().start() except RuntimeError: - print("Source has no sample rates (wrong device arguments?).", file=sys.stderr) + print "Source has no sample rates (wrong device arguments?)." sys.exit(1) # Set the antenna - if options.antenna: + if(options.antenna): self.src.set_antenna(options.antenna) # Set the clock source: @@ -172,6 +140,7 @@ class app_top_block(gr.top_block, Qt.QMainWindow): options.gain = float(r.start()+r.stop())/2 except RuntimeError: options.gain = 0 + pass else: options.gain = gain @@ -180,28 +149,19 @@ class app_top_block(gr.top_block, Qt.QMainWindow): if self._verbose: gain_names = self.src.get_gain_names() for name in gain_names: - rg = self.src.get_gain_range(name) - print("%s gain range: start %g stop %g step %g" % (name, rg.start(), rg.stop(), rg.step())) + range = self.src.get_gain_range(name) + print "%s gain range: start %d stop %d step %d" % (name, range.start(), range.stop(), range.step()) if options.gains: for tuple in options.gains.split(","): name, gain = tuple.split(":") gain = int(gain) - print("Setting gain %s to %g." % (name, gain)) + print "Setting gain %s to %d." % (name, gain) self.src.set_gain(gain, name) if self._verbose: rates = self.src.get_sample_rates() - print('Supported sample rates %.10g-%.10g step %.10g.' % (rates.start(), rates.stop(), rates.step())) - - self.bandwidth_ok = True - try: - rg = self.src.get_bandwidth_range() - range_start = rg.start() - if self._verbose: - print('Supported bandwidth rates %.10g-%.10g step %.10g.' % (rg.start(), rg.stop(), rg.step())) - except RuntimeError as ex: - self.bandwidth_ok = False + print 'Supported sample rates %d-%d step %d.' % (rates.start(), rates.stop(), rates.step()) if options.center_freq is None: freq = self.src.get_center_freq() @@ -211,99 +171,93 @@ class app_top_block(gr.top_block, Qt.QMainWindow): # if no freq was specified, use the mid-point in Hz r = self.src.get_freq_range() options.center_freq = float(r.start()+r.stop())/2 - if self._verbose: - print("Using auto-calculated mid-point frequency") input_rate = self.src.set_sample_rate(options.samp_rate) self.src.set_bandwidth(input_rate) - if self._verbose: - ranges = self.src.get_freq_range() - print("Supported frequencies %s-%s"%(eng_notation.num_to_str(ranges.start()), eng_notation.num_to_str(ranges.stop()))) + self.publish(SAMP_RANGE_KEY, self.src.get_sample_rates) + self.publish(FREQ_RANGE_KEY, self.src.get_freq_range) + for name in self.get_gain_names(): + self.publish(GAIN_RANGE_KEY(name), (lambda self=self,name=name: self.src.get_gain_range(name))) - for name in self.src.get_gain_names(): - print("GAIN(%s): %g"%(name, self.src.get_gain(name))) + self.publish(BWIDTH_RANGE_KEY, self.src.get_bandwidth_range) + + for name in self.get_gain_names(): + self.publish(GAIN_KEY(name), (lambda self=self,name=name: self.src.get_gain(name))) + + self.publish(BWIDTH_KEY, self.src.get_bandwidth) # initialize values from options - if options.freq_corr is not None: - self.set_freq_corr(options.freq_corr) + self[SAMP_RANGE_KEY] = self.src.get_sample_rates() + self[SAMP_RATE_KEY] = options.samp_rate + self[CENTER_FREQ_KEY] = options.center_freq + self[FREQ_CORR_KEY] = options.freq_corr + self['record'] = options.record self.dc_offset_mode = options.dc_offset_mode self.iq_balance_mode = options.iq_balance_mode # initialize reasonable defaults for DC / IQ correction - self.dc_offset_real = 0 - self.dc_offset_imag = 0 - self.iq_balance_mag = 0 - self.iq_balance_pha = 0 + self['dc_offset_real'] = 0 + self['dc_offset_imag'] = 0 + self['iq_balance_mag'] = 0 + self['iq_balance_pha'] = 0 + + #subscribe set methods + self.subscribe(SAMP_RATE_KEY, self.set_sample_rate) + + for name in self.get_gain_names(): + self.subscribe(GAIN_KEY(name), (lambda gain,self=self,name=name: self.set_named_gain(gain, name))) + + self.subscribe(BWIDTH_KEY, self.set_bandwidth) + self.subscribe(CENTER_FREQ_KEY, self.set_freq) + self.subscribe(FREQ_CORR_KEY, self.set_freq_corr) + + self.subscribe('dc_offset_real', self.set_dc_offset) + self.subscribe('dc_offset_imag', self.set_dc_offset) + self.subscribe('iq_balance_mag', self.set_iq_balance) + self.subscribe('iq_balance_pha', self.set_iq_balance) + + #force update on pubsub keys + #for key in (SAMP_RATE_KEY, BWIDTH_KEY, CENTER_FREQ_KEY, FREQ_CORR_KEY): + #print key, "=", self[key] + #self[key] = self[key] if options.fosphor: from gnuradio import fosphor - self.scope = fosphor.qt_sink_c() - self.scope.set_frequency_range(0, input_rate) - self.scope_win = sip.wrapinstance(self.scope.pyqwidget(), Qt.QWidget) - self.scope_win.setMinimumSize(800, 300) + self.scope = fosphor.wx_sink_c(panel, size=(800,300)) + self.scope.set_sample_rate(input_rate) + self.frame.SetMinSize((800,600)) elif options.waterfall: - self.scope = qtgui.waterfall_sink_c( - options.fft_size, - wintype=firdes.WIN_BLACKMAN_hARRIS, - fc=0, - bw=input_rate, - name="", - nconnections=1 - ) - self.scope.enable_grid(False) - self.scope.enable_axis_labels(True) - self.scope.set_intensity_range(-100, 20) - self.scope_win = sip.wrapinstance(self.scope.pyqwidget(), Qt.QWidget) - self.scope_win.setMinimumSize(800, 420) - + self.scope = waterfallsink2.waterfall_sink_c (panel, + fft_size=options.fft_size, + sample_rate=input_rate, + ref_scale=options.ref_scale, + ref_level=20.0, + y_divs = 12) + + self.scope.set_callback(self.wxsink_callback) + self.frame.SetMinSize((800, 420)) elif options.oscilloscope: - self.scope = qtgui.time_sink_c( - options.fft_size, - samp_rate=input_rate, - name="", - nconnections=1 - ) - self.scope_win = sip.wrapinstance(self.scope.pyqwidget(), Qt.QWidget) - self.scope_win.setMinimumSize(800, 600) - - elif options.qtgui: - self.scope = qtgui.sink_c( - options.fft_size, - wintype=firdes.WIN_BLACKMAN_hARRIS, - fc=0, - bw=input_rate, - name="", - plotfreq=True, - plotwaterfall=True, - plottime=True, - plotconst=True - ) - self.scope_win = sip.wrapinstance(self.scope.pyqwidget(), Qt.QWidget) - self.scope.set_update_time(1.0/10) - self.scope_win.setMinimumSize(800, 600) - + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) + self.frame.SetMinSize((800, 600)) else: - self.scope = qtgui.freq_sink_c( - fftsize=options.fft_size, - wintype=firdes.WIN_BLACKMAN_hARRIS, - fc=0, - bw=input_rate, - name="", - nconnections=1 - ) - self.scope_win = sip.wrapinstance(self.scope.pyqwidget(), Qt.QWidget) - self.scope.disable_legend() - self.scope_win.setMinimumSize(800, 420) - - self.connect((self.src, 0), (self.scope, 0)) - try: - self.freq = freq_recv(self.set_freq) - self.msg_connect((self.scope, 'freq'), (self.freq, 'msg')) - except RuntimeError: - self.freq = None + self.scope = fftsink2.fft_sink_c (panel, + fft_size=options.fft_size, + sample_rate=input_rate, + ref_scale=options.ref_scale, + ref_level=20.0, + y_divs = 12, + average=options.averaging, + peak_hold=options.peak_hold, + avg_alpha=options.avg_alpha, + fft_rate=options.fft_rate) + + self.scope.set_callback(self.wxsink_callback) + self.frame.SetMinSize((800, 420)) + + self.connect(self.src, self.scope) self.file_sink = blocks.file_sink(gr.sizeof_gr_complex, "/dev/null", False) self.file_sink.set_unbuffered(False) @@ -311,404 +265,586 @@ class app_top_block(gr.top_block, Qt.QMainWindow): # lock/connect/unlock at record button event did not work, so we leave it connected at all times self.connect(self.src, self.file_sink) - self._build_gui() + self._build_gui(vbox) + + if self.dc_offset_mode != None: + self.set_dc_offset_mode(self.dc_offset_mode) + + if self.iq_balance_mode != None: + self.set_iq_balance_mode(self.iq_balance_mode) # set initial values - if not self.set_freq(options.center_freq): + if not(self.set_freq(options.center_freq)): self._set_status_msg("Failed to set initial frequency") - if options.record is not None: - self._fre.insert(options.record) def record_to_filename(self): - s = self._fre.text() + s = self['record'] s = s.replace('%S', '%e' % self.src.get_sample_rate()) s = s.replace('%F', '%e' % self.src.get_center_freq()) s = s.replace('%T', datetime.datetime.now().strftime('%Y%m%d%H%M%S')) return s - def _set_status_msg(self, msg, timeout=0): - self.status.showMessage(msg, timeout) + def wxsink_callback(self, x, y): + self.set_freq_from_callback(x) - def _shrink(self, widget): - """Try to shrink RangeWidget by removing unnecessary margins""" - try: - widget.layout().setContentsMargins(0, 0, 0, 0) - widget.children()[0].layout().setContentsMargins(0, 0, 0, 0) - except: - pass + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) - def _add_section(self, text, layout): - """Add a section header to the GUI""" - frame = Qt.QWidget() - frame_layout = Qt.QHBoxLayout() - frame_layout.setContentsMargins(0, 0, 0, 0) - frame.setLayout(frame_layout) - - wid = Qt.QLabel() - wid.setText(text) - wid.setStyleSheet("font-weight: bold;") - frame_layout.addWidget(wid) - wid = Qt.QFrame() - wid.setFrameShape(Qt.QFrame.HLine) - frame_layout.addWidget(wid) - frame_layout.setStretchFactor(wid, 1) - - layout.addWidget(frame) - - def _chooser(self, names, callback, default=0): - """A simple radio-button chooser""" - buttons = Qt.QWidget() - blayout = Qt.QHBoxLayout() - bgroup = Qt.QButtonGroup() - buttons.setObjectName("foo") - buttons.setStyleSheet("QWidget#foo {border: 1px outset grey;}") - buttons.setLayout(blayout) - chooser = [] - for (num, txt) in enumerate(names): - rb = Qt.QRadioButton(txt) - rb.clicked.connect(partial(callback, num)) - chooser.append(rb) - bgroup.addButton(rb,num) - blayout.addWidget(rb) - if num == default: - rb.setChecked(True) - return buttons - - def _build_gui(self): - - self.top_widget = Qt.QWidget() - - self.top_layout = Qt.QVBoxLayout(self.top_widget) - self.top_layout.addWidget(self.scope_win) - - self.setCentralWidget(self.top_widget) - - self.status = Qt.QStatusBar() - self.setStatusBar(self.status) - self.status.setStyleSheet("QStatusBar{border-top: 1px outset grey;}") - - if hasattr(RangeWidget, 'EngSlider'): - eng_widget="eng_slider" - else: - eng_widget="counter_slider" + def _build_gui(self, vbox): + + if hasattr(self.scope, 'win'): + vbox.Add(self.scope.win, 1, wx.EXPAND) + vbox.AddSpacer(3) + + # add control area at the bottom + self.myform = myform = form.form() ################################################## # Frequency controls ################################################## - self._add_section("Frequency", self.top_layout) + fc_vbox = forms.static_box_sizer(parent=self.panel, + label="Center Frequency", + orient=wx.VERTICAL, + bold=True) + fc_vbox.AddSpacer(3) + # First row of frequency controls (center frequency) + freq_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(freq_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(5) + # Second row of frequency controls (freq. correction) + corr_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(corr_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(3) + + # Add frequency controls to top window sizer + vbox.Add(fc_vbox, 0, wx.EXPAND) + vbox.AddSpacer(5) + + freq_hbox.AddSpacer(3) + forms.text_box( + parent=self.panel, sizer=freq_hbox, + label='Center Frequency (Hz)', + proportion=1, + converter=forms.float_converter(), + ps=self, + key=CENTER_FREQ_KEY, + ) + freq_hbox.AddSpacer(5) + + try: # range.start() == range.stop() in file= mode + + forms.slider( + parent=self.panel, sizer=freq_hbox, + proportion=3, + ps=self, + key=CENTER_FREQ_KEY, + minimum=self[FREQ_RANGE_KEY].start(), + maximum=self[FREQ_RANGE_KEY].stop(), + num_steps=1000, + ) + freq_hbox.AddSpacer(3) - r = self.src.get_freq_range() - self._fr = Range(r.start(), r.stop(), (r.start()+r.stop())/100, self.src.get_center_freq(), 200) - self._fw = RangeWidget(self._fr, self.set_freq, 'Center Frequency (Hz)', eng_widget, float) - self._shrink(self._fw) - self.top_layout.addWidget(self._fw) + except AssertionError: + pass - if hasattr(self, 'ppm') and self.ppm is not None: - self._fcr = Range(-100, 100, 0.1, self.src.get_freq_corr(), 200) - self._fcw = RangeWidget(self._fcr, self.set_freq_corr, 'Freq. Correction (ppm)', "counter_slider", float) - self._shrink(self._fcw) - self.top_layout.addWidget(self._fcw) + if self[FREQ_CORR_KEY] != None: # show frequency correction scrollbar + + corr_hbox.AddSpacer(3) + forms.text_box( + parent=self.panel, sizer=corr_hbox, + label='Freq. Correction (ppm)', + proportion=1, + converter=forms.float_converter(), + ps=self, + key=FREQ_CORR_KEY, + ) + corr_hbox.AddSpacer(5) + + forms.slider( + parent=self.panel, sizer=corr_hbox, + proportion=3, + ps=self, + key=FREQ_CORR_KEY, + minimum=-100, + maximum=+100, + num_steps=2010, + step_size=0.1, + ) + corr_hbox.AddSpacer(3) ################################################## # Gain controls ################################################## - self._add_section("Gains", self.top_layout) - - self._gr={} - self._gw={} - for gain_name in self.src.get_gain_names(): - rg = self.src.get_gain_range(gain_name) - self._gr[gain_name] = Range(rg.start(), rg.stop(), rg.step(), self.src.get_gain(gain_name), 100) - self._gw[gain_name] = RangeWidget(self._gr[gain_name], partial(self.set_named_gain,name=gain_name), '%s Gain (dB):'%gain_name, "counter_slider", float) - self._shrink(self._gw[gain_name]) - self._gw[gain_name].d_widget.counter.setDecimals(2) - self.top_layout.addWidget(self._gw[gain_name]) + gc_vbox = forms.static_box_sizer(parent=self.panel, + label="Gain Settings", + orient=wx.VERTICAL, + bold=True) + gc_vbox.AddSpacer(3) + + # Add gain controls to top window sizer + vbox.Add(gc_vbox, 0, wx.EXPAND) + vbox.AddSpacer(5) + + for gain_name in self.get_gain_names(): + range = self[GAIN_RANGE_KEY(gain_name)] + gain = self[GAIN_KEY(gain_name)] + + #print gain_name, gain, range.to_pp_string() + if range.start() < range.stop(): + gain_hbox = wx.BoxSizer(wx.HORIZONTAL) + gc_vbox.Add(gain_hbox, 0, wx.EXPAND) + gc_vbox.AddSpacer(3) + + gain_hbox.AddSpacer(3) + forms.text_box( + parent=self.panel, sizer=gain_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self, + key=GAIN_KEY(gain_name), + label=gain_name + " Gain (dB)", + ) + gain_hbox.AddSpacer(5) + forms.slider( + parent=self.panel, sizer=gain_hbox, + proportion=3, + ps=self, + key=GAIN_KEY(gain_name), + minimum=range.start(), + maximum=range.stop(), + step_size=range.step() or (range.stop() - range.start())/10, + ) + gain_hbox.AddSpacer(3) ################################################## # Bandwidth controls ################################################## - if self.bandwidth_ok: - self._add_section("Bandwidth", self.top_layout) + try: + + bw_range = self[BWIDTH_RANGE_KEY] + #print bw_range.to_pp_string() + if bw_range.start() < bw_range.stop(): + bwidth_vbox = forms.static_box_sizer(parent=self.panel, + label="Bandwidth", + orient=wx.VERTICAL, + bold=True) + bwidth_vbox.AddSpacer(3) + bwidth_hbox = wx.BoxSizer(wx.HORIZONTAL) + bwidth_vbox.Add(bwidth_hbox, 0, wx.EXPAND) + bwidth_vbox.AddSpacer(3) + + vbox.Add(bwidth_vbox, 0, wx.EXPAND) + vbox.AddSpacer(5) + + bwidth_hbox.AddSpacer(3) + forms.text_box( + parent=self.panel, sizer=bwidth_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self, + key=BWIDTH_KEY, + label="Bandwidth (Hz)", + ) + bwidth_hbox.AddSpacer(5) + forms.slider( + parent=self.panel, sizer=bwidth_hbox, + proportion=3, + ps=self, + key=BWIDTH_KEY, + minimum=bw_range.start(), + maximum=bw_range.stop(), + step_size=bw_range.step() or (bw_range.stop() - bw_range.start())/100, + ) + bwidth_hbox.AddSpacer(3) + + except RuntimeError: + pass - r = self.src.get_bandwidth_range() - self._bwr = Range(r.start(), r.stop(), r.step() or (r.stop() - r.start())/100, self.src.get_bandwidth(), 100) - self._bww = RangeWidget(self._bwr, self.set_bandwidth, 'Bandwidth (Hz):', eng_widget, float) - self._shrink(self._bww) - self.top_layout.addWidget(self._bww) ################################################## # Sample rate controls ################################################## - self._add_section("Sample Rate", self.top_layout) + sr_vbox = forms.static_box_sizer(parent=self.panel, + label="Sample Rate", + orient=wx.VERTICAL, + bold=True) + sr_vbox.AddSpacer(3) + # First row of sample rate controls + sr_hbox = wx.BoxSizer(wx.HORIZONTAL) + sr_vbox.Add(sr_hbox, 0, wx.EXPAND) + sr_vbox.AddSpacer(5) + + # Add sample rate controls to top window sizer + vbox.Add(sr_vbox, 0, wx.EXPAND) + vbox.AddSpacer(5) + + sr_hbox.AddSpacer(3) + self.sample_rate_text = forms.text_box( + parent=self.panel, sizer=sr_hbox, + label='Sample Rate (Hz)', + proportion=1, + converter=forms.float_converter(), + ps=self, + key=SAMP_RATE_KEY, + ) + sr_hbox.AddSpacer(5) + + #forms.slider( + # parent=self.panel, sizer=sr_hbox, + # proportion=3, + # ps=self, + # key=SAMP_RATE_KEY, + # minimum=self[SAMP_RANGE_KEY].start(), + # maximum=self[SAMP_RANGE_KEY].stop(), + # step_size=self[SAMP_RANGE_KEY].step(), + #) + #sr_hbox.AddSpacer(3) - r = self.src.get_sample_rates() - self._srr = Range(r.start(), r.stop(), r.step() or (r.stop() - r.start())/100, self.src.get_sample_rate(), 100) - self._srw = RangeWidget(self._srr, self.set_sample_rate, 'Sample Rate (Hz)', eng_widget, float) - self._shrink(self._srw) - self.top_layout.addWidget(self._srw) ################################################## # File recording controls ################################################## - self._add_section("File recording", self.top_layout) - - wid = Qt.QWidget() - - layout = Qt.QHBoxLayout() - layout.setContentsMargins(0, 0, 0, 0) - - self._frl = Qt.QLabel('File Name') - layout.addWidget(self._frl) - - self._fre = Qt.QLineEdit() - layout.addWidget(self._fre) - - self._frb = Qt.QPushButton('REC') - layout.addWidget(self._frb) - - wid.setLayout(layout) - self.top_layout.addWidget(wid) - - self.recording = 0 - def record_callback(): - self.recording = 1-self.recording - if self.recording: - self._srw.setDisabled(True) - self._fre.setDisabled(True) - self._frb.setText('STOP') + rec_vbox = forms.static_box_sizer(parent=self.panel, + label="File recording", + orient=wx.VERTICAL, + bold=True) + rec_vbox.AddSpacer(3) + # First row of sample rate controls + rec_hbox = wx.BoxSizer(wx.HORIZONTAL) + rec_vbox.Add(rec_hbox, 0, wx.EXPAND) + rec_vbox.AddSpacer(5) + + # Add sample rate controls to top window sizer + vbox.Add(rec_vbox, 0, wx.EXPAND) + vbox.AddSpacer(5) + + rec_hbox.AddSpacer(3) + self.record_text = forms.text_box( + parent=self.panel, sizer=rec_hbox, + label='File Name', + proportion=1, + ps=self, + key='record', + converter=forms.str_converter(), + ) + rec_hbox.AddSpacer(5) + + def record_callback(value): + if value: + self.sample_rate_text.Disable() + self.record_text.Disable() self.rec_file_name = self.record_to_filename() - print("Recording samples to ", self.rec_file_name) + print "Recording samples to ", self.rec_file_name self.file_sink.open(self.rec_file_name); else: - self._srw.setDisabled(False) - self._fre.setDisabled(False) - self._frb.setText('REC') + self.sample_rate_text.Enable() + self.record_text.Enable() self.file_sink.close() - print("Finished recording to", self.rec_file_name) + print "Finished recording to", self.rec_file_name - self._fre.returnPressed.connect(record_callback) - self._frb.clicked.connect(record_callback) + forms.toggle_button( + sizer=rec_hbox, + parent=self.panel, + false_label='REC', + true_label='STOP', + value=False, + callback=record_callback, + ) ################################################## # DC Offset controls ################################################## if self.dc_offset_mode != None: - self._add_section("DC Offset Correction", self.top_layout) - - wid = Qt.QWidget() - layout = Qt.QHBoxLayout() - layout.setContentsMargins(0, 0, 0, 0) - - self._dcb = self._chooser(["Off", "Manual", "Auto"], self.set_dc_offset_mode, self.dc_offset_mode) - layout.addWidget(self._dcb) - - self._dcrr = Range(-1, +1, 0.001, 0, 20) - self._dcrw = RangeWidget(self._dcrr, self.set_dc_offset_real, 'Real', "counter_slider", float) - self._shrink(self._dcrw) - layout.addWidget(self._dcrw) - - self._dcir = Range(-1, +1, 0.001, 0, 20) - self._dciw = RangeWidget(self._dcrr, self.set_dc_offset_imag, 'Imag', "counter_slider", float) - self._shrink(self._dciw) - layout.addWidget(self._dciw) - - wid.setLayout(layout) - self.top_layout.addWidget(wid) + dc_offset_vbox = forms.static_box_sizer(parent=self.panel, + label="DC Offset Correction", + orient=wx.VERTICAL, + bold=True) + dc_offset_vbox.AddSpacer(3) + # First row of sample rate controls + dc_offset_hbox = wx.BoxSizer(wx.HORIZONTAL) + dc_offset_vbox.Add(dc_offset_hbox, 0, wx.EXPAND) + dc_offset_vbox.AddSpacer(3) + + # Add frequency controls to top window sizer + vbox.Add(dc_offset_vbox, 0, wx.EXPAND) + vbox.AddSpacer(3) + + self.dc_offset_mode_chooser = forms.radio_buttons( + parent=self.panel, + value=self.dc_offset_mode, + callback=self.set_dc_offset_mode, + label='', + choices=[0, 1, 2], + labels=["Off", "Manual", "Auto"], + style=wx.RA_HORIZONTAL, + ) + dc_offset_hbox.Add(self.dc_offset_mode_chooser) + dc_offset_hbox.AddSpacer(3) + + dc_offset_hbox.AddSpacer(3) + self.dc_offset_real_text = forms.text_box( + parent=self.panel, sizer=dc_offset_hbox, + label='Real', + proportion=1, + converter=forms.float_converter(), + ps=self, + key='dc_offset_real', + ) + dc_offset_hbox.AddSpacer(3) + + self.dc_offset_real_slider = forms.slider( + parent=self.panel, sizer=dc_offset_hbox, + proportion=3, + minimum=-1, + maximum=+1, + step_size=0.001, + ps=self, + key='dc_offset_real', + ) + dc_offset_hbox.AddSpacer(3) + + dc_offset_hbox.AddSpacer(3) + self.dc_offset_imag_text = forms.text_box( + parent=self.panel, sizer=dc_offset_hbox, + label='Imag', + proportion=1, + converter=forms.float_converter(), + ps=self, + key='dc_offset_imag', + ) + dc_offset_hbox.AddSpacer(3) + + self.dc_offset_imag_slider = forms.slider( + parent=self.panel, sizer=dc_offset_hbox, + proportion=3, + minimum=-1, + maximum=+1, + step_size=0.001, + ps=self, + key='dc_offset_imag', + ) + dc_offset_hbox.AddSpacer(3) ################################################## # IQ Imbalance controls ################################################## if self.iq_balance_mode != None: - self._add_section("IQ Imbalance Correction", self.top_layout) - - wid = Qt.QWidget() - - layout = Qt.QHBoxLayout() - layout.setContentsMargins(0, 0, 0, 0) - - self._iqb = self._chooser(["Off", "Manual", "Auto"], self.set_dc_offset_mode, self.iq_balance_mode) - layout.addWidget(self._iqb) - - self._iqmr = Range(-1, +1, 0.001, 0, 20) - self._iqmw = RangeWidget(self._iqmr, self.set_iq_balance_mag, 'Mag', "counter_slider", float) - self._shrink(self._iqmw) - layout.addWidget(self._iqmw) - - self._iqpr = Range(-1, +1, 0.001, 0, 20) - self._iqpw = RangeWidget(self._iqpr, self.set_iq_balance_pha, 'Pha', "counter_slider", float) - self._shrink(self._iqpw) - layout.addWidget(self._iqpw) - wid.setLayout(layout) - self.top_layout.addWidget(wid) + iq_balance_vbox = forms.static_box_sizer(parent=self.panel, + label="IQ Imbalance Correction", + orient=wx.VERTICAL, + bold=True) + iq_balance_vbox.AddSpacer(3) + # First row of sample rate controls + iq_balance_hbox = wx.BoxSizer(wx.HORIZONTAL) + iq_balance_vbox.Add(iq_balance_hbox, 0, wx.EXPAND) + iq_balance_vbox.AddSpacer(3) + + # Add frequency controls to top window sizer + vbox.Add(iq_balance_vbox, 0, wx.EXPAND) + vbox.AddSpacer(3) + + self.iq_balance_mode_chooser = forms.radio_buttons( + parent=self.panel, + value=self.iq_balance_mode, + callback=self.set_iq_balance_mode, + label='', + choices=[0, 1, 2], + labels=["Off", "Manual", "Auto"], + style=wx.RA_HORIZONTAL, + ) + iq_balance_hbox.Add(self.iq_balance_mode_chooser) + iq_balance_hbox.AddSpacer(3) + + iq_balance_hbox.AddSpacer(3) + self.iq_balance_mag_text = forms.text_box( + parent=self.panel, sizer=iq_balance_hbox, + label='Mag', + proportion=1, + converter=forms.float_converter(), + ps=self, + key='iq_balance_mag', + ) + iq_balance_hbox.AddSpacer(3) + + self.iq_balance_mag_slider = forms.slider( + parent=self.panel, sizer=iq_balance_hbox, + proportion=3, + minimum=-1, + maximum=+1, + step_size=0.001, + ps=self, + key='iq_balance_mag', + ) + iq_balance_hbox.AddSpacer(3) + + iq_balance_hbox.AddSpacer(3) + self.iq_balance_pha_text = forms.text_box( + parent=self.panel, sizer=iq_balance_hbox, + label='Phase', + proportion=1, + converter=forms.float_converter(), + ps=self, + key='iq_balance_pha', + ) + iq_balance_hbox.AddSpacer(3) + + self.iq_balance_pha_slider = forms.slider( + parent=self.panel, sizer=iq_balance_hbox, + proportion=3, + minimum=-1, + maximum=+1, + step_size=0.001, + ps=self, + key='iq_balance_pha', + ) + iq_balance_hbox.AddSpacer(3) def set_dc_offset_mode(self, dc_offset_mode): if dc_offset_mode == 1: - self._dcrw.setDisabled(False) - self._dciw.setDisabled(False) + self.dc_offset_real_text.Enable() + self.dc_offset_real_slider.Enable() + self.dc_offset_imag_text.Enable() + self.dc_offset_imag_slider.Enable() - self.set_dc_offset() + self.set_dc_offset(0) else: - self._dcrw.setDisabled(True) - self._dciw.setDisabled(True) + self.dc_offset_real_text.Disable() + self.dc_offset_real_slider.Disable() + self.dc_offset_imag_text.Disable() + self.dc_offset_imag_slider.Disable() self.dc_offset_mode = dc_offset_mode self.src.set_dc_offset_mode(dc_offset_mode) + self.dc_offset_mode_chooser.set_value(self.dc_offset_mode) - def set_dc_offset_real(self, value): - self.dc_offset_real = value - self.set_dc_offset() - - def set_dc_offset_imag(self, value): - self.dc_offset_imag = value - self.set_dc_offset() - - def set_dc_offset(self): - correction = complex(self.dc_offset_real, self.dc_offset_imag) + def set_dc_offset(self, value): + correction = complex( self['dc_offset_real'], self['dc_offset_imag'] ) try: - self.src.set_dc_offset(correction) + self.src.set_dc_offset( correction ) if self._verbose: - print("Set DC offset to", correction) + print "Set DC offset to", correction except RuntimeError as ex: - print(ex) + print ex def set_iq_balance_mode(self, iq_balance_mode): if iq_balance_mode == 1: - self._iqpw.setDisabled(False) - self._iqmw.setDisabled(False) + self.iq_balance_mag_text.Enable() + self.iq_balance_mag_slider.Enable() + self.iq_balance_pha_text.Enable() + self.iq_balance_pha_slider.Enable() - self.set_iq_balance() + self.set_iq_balance(0) else: - self._iqpw.setDisabled(True) - self._iqmw.setDisabled(True) + self.iq_balance_mag_text.Disable() + self.iq_balance_mag_slider.Disable() + self.iq_balance_pha_text.Disable() + self.iq_balance_pha_slider.Disable() self.iq_balance_mode = iq_balance_mode self.src.set_iq_balance_mode(iq_balance_mode) + self.iq_balance_mode_chooser.set_value(self.iq_balance_mode) - def set_iq_balance_mag(self, value): - self.iq_balance_mag = value - self.set_iq_balance() - - def set_iq_balance_pha(self, value): - self.iq_balance_pha = value - self.set_iq_balance() - - def set_iq_balance(self): - correction = complex(self.iq_balance_mag, self.iq_balance_pha) + def set_iq_balance(self, value): + correction = complex( self['iq_balance_mag'], self['iq_balance_pha'] ) try: - self.src.set_iq_balance(correction) + self.src.set_iq_balance( correction ) if self._verbose: - print("Set IQ balance to", correction) + print "Set IQ balance to", correction except RuntimeError as ex: - print(ex) + print ex def set_sample_rate(self, samp_rate): samp_rate = self.src.set_sample_rate(samp_rate) - if hasattr(self.scope, 'set_frequency_range'): - self.scope.set_frequency_range(self.src.get_center_freq(), samp_rate) if hasattr(self.scope, 'set_sample_rate'): self.scope.set_sample_rate(samp_rate) if self._verbose: - print("Set sample rate to:", samp_rate) + print "Set sample rate to:", samp_rate try: - if hasattr(self._bww.d_widget, 'setValue'): - self._bww.d_widget.setValue(samp_rate) - else: - self._bww.d_widget.counter.setValue(samp_rate) - except (RuntimeError, AttributeError): + self[BWIDTH_KEY] = self.set_bandwidth(samp_rate) + except RuntimeError: pass return samp_rate + def get_gain_names(self): + return self.src.get_gain_names() + def set_named_gain(self, gain, name): - if self._verbose: - print("Trying to set " + name + " gain to:", gain) + if gain is None: + g = self[GAIN_RANGE_KEY(name)] + gain = float(g.start()+g.stop())/2 + if self._verbose: + print "Using auto-calculated mid-point gain" + self[GAIN_KEY(name)] = gain + return gain = self.src.set_gain(gain, name) if self._verbose: - print("Set " + name + " gain to:", gain) + print "Set " + name + " gain to:", gain def set_bandwidth(self, bw): - if self._verbose: - print("Trying to set bandwidth to:", bw) - clipped_bw = self.src.get_bandwidth_range().clip(bw) - if self._verbose: - print("Clipping bandwidth to:", clipped_bw) + clipped_bw = self[BWIDTH_RANGE_KEY].clip(bw) if self.src.get_bandwidth() != clipped_bw: bw = self.src.set_bandwidth(clipped_bw) if self._verbose: - print("Set bandwidth to:", bw) + print "Set bandwidth to:", bw return bw + def set_freq_from_callback(self, freq): + freq = self.src.set_center_freq(freq) + self[CENTER_FREQ_KEY] = freq; + def set_freq(self, freq): + if freq is None: + f = self[FREQ_RANGE_KEY] + freq = float(f.start()+f.stop())/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" + self[CENTER_FREQ_KEY] = freq + return freq = self.src.set_center_freq(freq) - if hasattr(self.scope, 'set_frequency_range'): - self.scope.set_frequency_range(freq, self.src.get_sample_rate()) if hasattr(self.scope, 'set_baseband_freq'): self.scope.set_baseband_freq(freq) - try: - if hasattr(self._fw.d_widget, 'setValue'): - self._fw.d_widget.setValue(freq) - else: - self._fw.d_widget.counter.setValue(freq) - except (RuntimeError, AttributeError): - pass - if freq is not None: if self._verbose: - print("Set center frequency to %.10g"%freq) + print "Set center frequency to", freq elif self._verbose: - print("Failed to set freq.") + print "Failed to set freq." return freq def set_freq_corr(self, ppm): - self.ppm = self.src.set_freq_corr(ppm) - if self._verbose: - print("Set frequency correction to:", self.ppm) - - -def main(): - qapp = Qt.QApplication(sys.argv) - - tb = app_top_block(qapp.arguments(), "osmocom Spectrum Browser") - tb.start() - tb.show() - - def sig_handler(sig=None, frame=None): - print("caught signal") - Qt.QApplication.quit() - - signal.signal(signal.SIGINT, sig_handler) - signal.signal(signal.SIGTERM, sig_handler) - - # this timer is necessary for signals (^C) to work - timer = Qt.QTimer() - timer.start(500) - timer.timeout.connect(lambda: None) + if ppm is None: + ppm = 0.0 + if self._verbose: + print "Using frequency corrrection of", ppm + self[FREQ_CORR_KEY] = ppm + return - def quitting(): - tb.stop() - tb.wait() - qapp.aboutToQuit.connect(quitting) - qapp.exec_() + ppm = self.src.set_freq_corr(ppm) + if self._verbose: + print "Set frequency correction to:", ppm +def main (): + app = stdgui2.stdapp(app_top_block, "osmocom Spectrum Browser", nstatus=1) + app.MainLoop() if __name__ == '__main__': - main() + main () diff --git a/apps/osmocom_siggen b/apps/osmocom_siggen index 1727f44..bd92eac 100755 --- a/apps/osmocom_siggen +++ b/apps/osmocom_siggen @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # Copyright 2009,2011,2012 Free Software Foundation, Inc. # diff --git a/apps/osmocom_siggen_nogui b/apps/osmocom_siggen_nogui index 5370cd0..0283fcf 100755 --- a/apps/osmocom_siggen_nogui +++ b/apps/osmocom_siggen_nogui @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # Copyright 2008,2009,2011,2012 Free Software Foundation, Inc. # @@ -26,19 +26,19 @@ import sys def main(): if gr.enable_realtime_scheduling() != gr.RT_OK: - print("Note: failed to enable realtime scheduling, continuing") + print "Note: failed to enable realtime scheduling, continuing" # Grab command line options and create top block try: (options, args) = osmocom_siggen.get_options() tb = osmocom_siggen.top_block(options, args) - except RuntimeError as e: - print(e) + except RuntimeError, e: + print e sys.exit(1) tb.start() - input('Press Enter to quit: ') + raw_input('Press Enter to quit: ') tb.stop() tb.wait() diff --git a/apps/osmocom_spectrum_sense b/apps/osmocom_spectrum_sense index 9fea6f0..ea365bb 100755 --- a/apps/osmocom_spectrum_sense +++ b/apps/osmocom_spectrum_sense @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # Copyright 2005,2007,2011 Free Software Foundation, Inc. # @@ -71,13 +71,13 @@ class tune(gr.feval_dd): # wait until msgq is empty before continuing while(self.tb.msgq.full_p()): - #print("msgq full, holding..") + #print "msgq full, holding.." time.sleep(0.1) return new_freq - except Exception as e: - print("tune: Exception: ", e) + except Exception, e: + print "tune: Exception: ", e class parse_msg(object): @@ -147,7 +147,7 @@ class my_top_block(gr.top_block): realtime = True else: realtime = False - print("Note: failed to enable realtime scheduling") + print "Note: failed to enable realtime scheduling" # build graph self.u = osmosdr.source(options.args) @@ -155,7 +155,7 @@ class my_top_block(gr.top_block): try: self.u.get_sample_rates().start() except RuntimeError: - print("Source has no sample rates (wrong device arguments?).") + print "Source has no sample rates (wrong device arguments?)." sys.exit(1) # Set the antenna @@ -218,7 +218,7 @@ class my_top_block(gr.top_block): options.gain = float(g.start()+g.stop())/2.0 self.set_gain(options.gain) - print("gain =", options.gain) + print "gain =", options.gain def set_next_freq(self): target_freq = self.next_freq @@ -227,7 +227,7 @@ class my_top_block(gr.top_block): self.next_freq = self.min_center_freq if not self.set_freq(target_freq): - print("Failed to set frequency to", target_freq) + print "Failed to set frequency to", target_freq sys.exit(1) return target_freq @@ -259,9 +259,9 @@ def main_loop(tb): def bin_freq(i_bin, center_freq): #hz_per_bin = tb.usrp_rate / tb.fft_size freq = center_freq - (tb.usrp_rate / 2) + (tb.channel_bandwidth * i_bin) - #print("freq original:",freq) + #print "freq original:",freq #freq = nearest_freq(freq, tb.channel_bandwidth) - #print("freq rounded:",freq) + #print "freq rounded:",freq return freq bin_start = int(tb.fft_size * ((1 - 0.75) / 2)) @@ -287,7 +287,7 @@ def main_loop(tb): power_db = 10*math.log10(m.data[i_bin]/tb.usrp_rate) - noise_floor_db if (power_db > tb.squelch_threshold) and (freq >= tb.min_freq) and (freq <= tb.max_freq): - print(datetime.now(), "center_freq", center_freq, "freq", freq, "power_db", power_db, "noise_floor_db", noise_floor_db) + print datetime.now(), "center_freq", center_freq, "freq", freq, "power_db", power_db, "noise_floor_db", noise_floor_db if __name__ == '__main__': t = ThreadClass() diff --git a/cmake/Modules/CMakeParseArgumentsCopy.cmake b/cmake/Modules/CMakeParseArgumentsCopy.cmake new file mode 100644 index 0000000..66016cb --- /dev/null +++ b/cmake/Modules/CMakeParseArgumentsCopy.cmake @@ -0,0 +1,138 @@ +# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for +# parsing the arguments given to that macro or function. +# It processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The <options> argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any value +# following, like e.g. the OPTIONAL keyword of the install() command. +# +# The <one_value_keywords> argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The <multi_value_keywords> argument contains all keywords for this macro +# which can be followed by more than one value, like e.g. the TARGETS or +# FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in <options>, <one_value_keywords> and +# <multi_value_keywords> a variable composed of the given <prefix> +# followed by "_" and the name of the respective keyword. +# These variables will then hold the respective value from the argument list. +# For the <options> keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see whether +# your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments as the +# real install() command: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) +# ... +# +# Assume my_install() has been called like this: +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# After the cmake_parse_arguments() call the macro will have set the following +# variables: +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# You can the continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a one_value_keyword +# another recognized keyword follows, this is interpreted as the beginning of +# the new option. +# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would +# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore. + +#============================================================================= +# Copyright 2010 Alexander Neundorf <neundorf@kde.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach(arg_name) + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach(option) + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else(insideValues) + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif(insideValues) + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach(currentArg) + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach(arg_name) + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) diff --git a/cmake/Modules/FindGnuradioFCD.cmake b/cmake/Modules/FindGnuradioFCD.cmake new file mode 100644 index 0000000..e7d7670 --- /dev/null +++ b/cmake/Modules/FindGnuradioFCD.cmake @@ -0,0 +1,34 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_GNURADIO_FCD gnuradio-fcd) + +FIND_PATH( + GNURADIO_FCD_INCLUDE_DIRS + NAMES gnuradio/fcd/api.h + HINTS $ENV{GNURADIO_FCD_DIR}/include + ${PC_GNURADIO_FCD_INCLUDEDIR} + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + GNURADIO_FCD_LIBRARIES + NAMES gnuradio-fcd + HINTS $ENV{GNURADIO_FCD_DIR}/lib + ${PC_GNURADIO_FCD_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +if(GNURADIO_FCD_INCLUDE_DIRS AND GNURADIO_FCD_LIBRARIES) + set(GNURADIO_FCD_FOUND TRUE CACHE INTERNAL "gnuradio-fcd found") + message(STATUS "Found gnuradio-fcd: ${GNURADIO_FCD_INCLUDE_DIRS}, ${GNURADIO_FCD_LIBRARIES}") +else(GNURADIO_FCD_INCLUDE_DIRS AND GNURADIO_FCD_LIBRARIES) + set(GNURADIO_FCD_FOUND FALSE CACHE INTERNAL "gnuradio-fcd found") + message(STATUS "gnuradio-fcd not found.") +endif(GNURADIO_FCD_INCLUDE_DIRS AND GNURADIO_FCD_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_FCD DEFAULT_MSG GNURADIO_FCD_LIBRARIES GNURADIO_FCD_INCLUDE_DIRS) +MARK_AS_ADVANCED(GNURADIO_FCD_LIBRARIES GNURADIO_FCD_INCLUDE_DIRS) diff --git a/cmake/Modules/FindGnuradioFCDPP.cmake b/cmake/Modules/FindGnuradioFCDPP.cmake index f81fe8a..c6f03f1 100644 --- a/cmake/Modules/FindGnuradioFCDPP.cmake +++ b/cmake/Modules/FindGnuradioFCDPP.cmake @@ -1,18 +1,25 @@ -if(NOT GNURADIO_FCDPP_FOUND) - pkg_check_modules (GNURADIO_FCDPP_PKG libgnuradio-fcdproplus) - find_path(GNURADIO_FCDPP_INCLUDE_DIRS NAMES fcdproplus/api.h - PATHS - ${GNURADIO_FCDPP_PKG_INCLUDE_DIRS} - /usr/include - /usr/local/include - ) +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_GNURADIO_FCDPP gnuradio-fcdproplus) - find_library(GNURADIO_FCDPP_LIBRARIES NAMES gnuradio-fcdproplus - PATHS - ${GNURADIO_FCDPP_PKG_LIBRARY_DIRS} - /usr/lib - /usr/local/lib - ) +FIND_PATH( + GNURADIO_FCDPP_INCLUDE_DIRS + NAMES fcdproplus/api.h + HINTS $ENV{GNURADIO_FCDPP_DIR}/include + ${PC_GNURADIO_FCDPP_INCLUDEDIR} + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + GNURADIO_FCDPP_LIBRARIES + NAMES gnuradio-fcdproplus + HINTS $ENV{GNURADIO_FCDPP_DIR}/lib + ${PC_GNURADIO_FCDPP_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) if(GNURADIO_FCDPP_INCLUDE_DIRS AND GNURADIO_FCDPP_LIBRARIES) set(GNURADIO_FCDPP_FOUND TRUE CACHE INTERNAL "gnuradio-fcdproplus found") @@ -22,6 +29,6 @@ else(GNURADIO_FCDPP_INCLUDE_DIRS AND GNURADIO_FCDPP_LIBRARIES) message(STATUS "gnuradio-fcdproplus not found.") endif(GNURADIO_FCDPP_INCLUDE_DIRS AND GNURADIO_FCDPP_LIBRARIES) -mark_as_advanced(GNURADIO_FCDPP_LIBRARIES GNURADIO_FCDPP_INCLUDE_DIRS) - -endif(NOT GNURADIO_FCDPP_FOUND) +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_FCDPP DEFAULT_MSG GNURADIO_FCDPP_LIBRARIES GNURADIO_FCDPP_INCLUDE_DIRS) +MARK_AS_ADVANCED(GNURADIO_FCDPP_LIBRARIES GNURADIO_FCDPP_INCLUDE_DIRS) diff --git a/cmake/Modules/FindGnuradioIQBalance.cmake b/cmake/Modules/FindGnuradioIQBalance.cmake new file mode 100644 index 0000000..c381d1c --- /dev/null +++ b/cmake/Modules/FindGnuradioIQBalance.cmake @@ -0,0 +1,29 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_GNURADIO_IQBALANCE gnuradio-iqbalance) + +FIND_PATH( + GNURADIO_IQBALANCE_INCLUDE_DIRS + NAMES gnuradio/iqbalance/api.h + HINTS $ENV{GNURADIO_IQBALANCE_DIR}/include + ${PC_GNURADIO_IQBALANCE_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + GNURADIO_IQBALANCE_LIBRARIES + NAMES gnuradio-iqbalance + HINTS $ENV{GNURADIO_IQBALANCE_DIR}/lib + ${PC_GNURADIO_IQBALANCE_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib64 + ${CMAKE_INSTALL_PREFIX}/lib + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_IQBALANCE DEFAULT_MSG GNURADIO_IQBALANCE_LIBRARIES GNURADIO_IQBALANCE_INCLUDE_DIRS) +MARK_AS_ADVANCED(GNURADIO_IQBALANCE_LIBRARIES GNURADIO_IQBALANCE_INCLUDE_DIRS) diff --git a/cmake/Modules/FindGnuradioUHD.cmake b/cmake/Modules/FindGnuradioUHD.cmake new file mode 100644 index 0000000..f99daf0 --- /dev/null +++ b/cmake/Modules/FindGnuradioUHD.cmake @@ -0,0 +1,34 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_GNURADIO_UHD gnuradio-uhd) + +FIND_PATH( + GNURADIO_UHD_INCLUDE_DIRS + NAMES gnuradio/uhd/api.h + HINTS $ENV{GNURADIO_UHD_DIR}/include + ${PC_GNURADIO_UHD_INCLUDEDIR} + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + GNURADIO_UHD_LIBRARIES + NAMES gnuradio-uhd + HINTS $ENV{GNURADIO_UHD_DIR}/lib + ${PC_GNURADIO_UHD_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +if(GNURADIO_UHD_INCLUDE_DIRS AND GNURADIO_UHD_LIBRARIES) + set(GNURADIO_UHD_FOUND TRUE CACHE INTERNAL "gnuradio-uhd found") + message(STATUS "Found gnuradio-uhd: ${GNURADIO_UHD_INCLUDE_DIRS}, ${GNURADIO_UHD_LIBRARIES}") +else(GNURADIO_UHD_INCLUDE_DIRS AND GNURADIO_UHD_LIBRARIES) + set(GNURADIO_UHD_FOUND FALSE CACHE INTERNAL "gnuradio-uhd found") + message(STATUS "gnuradio-uhd not found.") +endif(GNURADIO_UHD_INCLUDE_DIRS AND GNURADIO_UHD_LIBRARIES) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_UHD DEFAULT_MSG GNURADIO_UHD_LIBRARIES GNURADIO_UHD_INCLUDE_DIRS) +MARK_AS_ADVANCED(GNURADIO_UHD_LIBRARIES GNURADIO_UHD_INCLUDE_DIRS) diff --git a/cmake/Modules/FindLibAIRSPYHF.cmake b/cmake/Modules/FindLibAIRSPYHF.cmake deleted file mode 100644 index edb0dda..0000000 --- a/cmake/Modules/FindLibAIRSPYHF.cmake +++ /dev/null @@ -1,24 +0,0 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_LIBAIRSPYHF libairspyhf) - -FIND_PATH( - LIBAIRSPYHF_INCLUDE_DIRS - NAMES libairspyhf/airspyhf.h - HINTS $ENV{LIBAIRSPYHF_DIR}/include - ${PC_LIBAIRSPYHF_INCLUDEDIR} - PATHS /usr/local/include - /usr/include -) - -FIND_LIBRARY( - LIBAIRSPYHF_LIBRARIES - NAMES airspyhf - HINTS $ENV{LIBAIRSPYHF_DIR}/lib - ${PC_LIBAIRSPYHF_LIBDIR} - PATHS /usr/local/lib - /usr/lib -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBAIRSPYHF DEFAULT_MSG LIBAIRSPYHF_LIBRARIES LIBAIRSPYHF_INCLUDE_DIRS) -MARK_AS_ADVANCED(LIBAIRSPYHF_LIBRARIES LIBAIRSPYHF_INCLUDE_DIRS) diff --git a/cmake/Modules/FindLibMiriSDR.cmake b/cmake/Modules/FindLibMiriSDR.cmake new file mode 100644 index 0000000..cdb673f --- /dev/null +++ b/cmake/Modules/FindLibMiriSDR.cmake @@ -0,0 +1,27 @@ +if(NOT LIBMIRISDR_FOUND) + pkg_check_modules (LIBMIRISDR_PKG libmirisdr) + find_path(LIBMIRISDR_INCLUDE_DIRS NAMES mirisdr.h + PATHS + ${LIBMIRISDR_PKG_INCLUDE_DIRS} + /usr/include + /usr/local/include + ) + + find_library(LIBMIRISDR_LIBRARIES NAMES mirisdr + PATHS + ${LIBMIRISDR_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +if(LIBMIRISDR_INCLUDE_DIRS AND LIBMIRISDR_LIBRARIES) + set(LIBMIRISDR_FOUND TRUE CACHE INTERNAL "libmirisdr found") + message(STATUS "Found libmirisdr: ${LIBMIRISDR_INCLUDE_DIRS}, ${LIBMIRISDR_LIBRARIES}") +else(LIBMIRISDR_INCLUDE_DIRS AND LIBMIRISDR_LIBRARIES) + set(LIBMIRISDR_FOUND FALSE CACHE INTERNAL "libmirisdr found") + message(STATUS "libmirisdr not found.") +endif(LIBMIRISDR_INCLUDE_DIRS AND LIBMIRISDR_LIBRARIES) + +mark_as_advanced(LIBMIRISDR_LIBRARIES LIBMIRISDR_INCLUDE_DIRS) + +endif(NOT LIBMIRISDR_FOUND) diff --git a/cmake/Modules/FindLibOsmoSDR.cmake b/cmake/Modules/FindLibOsmoSDR.cmake new file mode 100644 index 0000000..a772e68 --- /dev/null +++ b/cmake/Modules/FindLibOsmoSDR.cmake @@ -0,0 +1,27 @@ +if(NOT LIBOSMOSDR_FOUND) + pkg_check_modules (LIBOSMOSDR_PKG libosmosdr) + find_path(LIBOSMOSDR_INCLUDE_DIRS NAMES osmosdr.h + PATHS + ${LIBOSMOSDR_PKG_INCLUDE_DIRS} + /usr/include + /usr/local/include + ) + + find_library(LIBOSMOSDR_LIBRARIES NAMES osmosdr + PATHS + ${LIBOSMOSDR_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +if(LIBOSMOSDR_INCLUDE_DIRS AND LIBOSMOSDR_LIBRARIES) + set(LIBOSMOSDR_FOUND TRUE CACHE INTERNAL "libosmosdr found") + message(STATUS "Found libosmosdr: ${LIBOSMOSDR_INCLUDE_DIRS}, ${LIBOSMOSDR_LIBRARIES}") +else(LIBOSMOSDR_INCLUDE_DIRS AND LIBOSMOSDR_LIBRARIES) + set(LIBOSMOSDR_FOUND FALSE CACHE INTERNAL "libosmosdr found") + message(STATUS "libosmosdr not found.") +endif(LIBOSMOSDR_INCLUDE_DIRS AND LIBOSMOSDR_LIBRARIES) + +mark_as_advanced(LIBOSMOSDR_LIBRARIES LIBOSMOSDR_INCLUDE_DIRS) + +endif(NOT LIBOSMOSDR_FOUND) diff --git a/cmake/Modules/FindLibXTRX.cmake b/cmake/Modules/FindLibXTRX.cmake deleted file mode 100644 index e7681d1..0000000 --- a/cmake/Modules/FindLibXTRX.cmake +++ /dev/null @@ -1,27 +0,0 @@ -if(NOT LIBXTRX_FOUND) - pkg_check_modules (LIBXTRX_PKG libxtrx) - find_path(LIBXTRX_INCLUDE_DIRS NAMES xtrx_api.h - PATHS - ${LIBXTRX_PKG_INCLUDE_DIRS} - /usr/include - /usr/local/include - ) - - find_library(LIBXTRX_LIBRARIES NAMES xtrx - PATHS - ${LIBXTRX_PKG_LIBRARY_DIRS} - /usr/lib - /usr/local/lib - ) - -if(LIBXTRX_INCLUDE_DIRS AND LIBXTRX_LIBRARIES) - set(LIBXTRX_FOUND TRUE CACHE INTERNAL "libxtrx found") - message(STATUS "Found libxtrx: ${LIBXTRX_INCLUDE_DIRS}, ${LIBXTRX_LIBRARIES}") -else(LIBXTRX_INCLUDE_DIRS AND LIBXTRX_LIBRARIES) - set(LIBXTRX_FOUND FALSE CACHE INTERNAL "libxtrx found") - message(STATUS "libxtrx not found.") -endif(LIBXTRX_INCLUDE_DIRS AND LIBXTRX_LIBRARIES) - -mark_as_advanced(LIBXTRX_LIBRARIES LIBXTRX_INCLUDE_DIRS) - -endif(NOT LIBXTRX_FOUND) diff --git a/cmake/Modules/FindLibbladeRF.cmake b/cmake/Modules/FindLibbladeRF.cmake index 0971344..fc67082 100644 --- a/cmake/Modules/FindLibbladeRF.cmake +++ b/cmake/Modules/FindLibbladeRF.cmake @@ -1,5 +1,9 @@ if(NOT LIBBLADERF_FOUND) pkg_check_modules (LIBBLADERF_PKG libbladeRF) + if (LIBBLADERF_PKG_FOUND AND LIBBLADERF_PKG_VERSION VERSION_LESS "2") + message( FATAL_ERROR "Install version 2 or greater of libbladeRF." + " Current version ( ${LIBBLADERF_PKG_VERSION} ) is out of date." ) + endif() find_path(LIBBLADERF_INCLUDE_DIRS NAMES libbladeRF.h PATHS ${LIBBLADERF_PKG_INCLUDE_DIRS} diff --git a/cmake/Modules/GrComponent.cmake b/cmake/Modules/GrComponent.cmake new file mode 100644 index 0000000..22b0ea4 --- /dev/null +++ b/cmake/Modules/GrComponent.cmake @@ -0,0 +1,115 @@ +# Copyright 2010-2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_GR_COMPONENT_CMAKE) + return() +endif() +set(__INCLUDED_GR_COMPONENT_CMAKE TRUE) + +set(_gr_enabled_components "" CACHE INTERNAL "" FORCE) +set(_gr_disabled_components "" CACHE INTERNAL "" FORCE) + +if(NOT DEFINED ENABLE_DEFAULT) + set(ENABLE_DEFAULT ON) + message(STATUS "") + message(STATUS "The build system will automatically enable all components.") + message(STATUS "Use -DENABLE_DEFAULT=OFF to disable components by default.") +endif() + +######################################################################## +# Register a component into the system +# - name: canonical component name +# - var: variable for enabled status +# - argn: list of dependencies +######################################################################## +function(GR_REGISTER_COMPONENT name var) + include(CMakeDependentOption) + message(STATUS "") + message(STATUS "Configuring ${name} support...") + foreach(dep ${ARGN}) + message(STATUS " Dependency ${dep} = ${${dep}}") + endforeach(dep) + + #if the user set the var to force, we note this + if("${${var}}" STREQUAL "FORCE") + set(${var} ON) + set(var_force TRUE) + else() + set(var_force FALSE) + endif() + + #rewrite the dependency list so that deps that are also components use the cached version + unset(comp_deps) + foreach(dep ${ARGN}) + list(FIND _gr_enabled_components ${dep} dep_enb_index) + list(FIND _gr_disabled_components ${dep} dep_dis_index) + if (${dep_enb_index} EQUAL -1 AND ${dep_dis_index} EQUAL -1) + list(APPEND comp_deps ${dep}) + else() + list(APPEND comp_deps ${dep}_cached) #is a component, use cached version + endif() + endforeach(dep) + + #setup the dependent option for this component + CMAKE_DEPENDENT_OPTION(${var} "enable ${name} support" ${ENABLE_DEFAULT} "${comp_deps}" OFF) + set(${var} "${${var}}" PARENT_SCOPE) + set(${var}_cached "${${var}}" CACHE INTERNAL "" FORCE) + + #force was specified, but the dependencies were not met + if(NOT ${var} AND var_force) + message(FATAL_ERROR "user force-enabled ${name} but configuration checked failed") + endif() + + #append the component into one of the lists + if(${var}) + message(STATUS " Enabling ${name} support.") + list(APPEND _gr_enabled_components ${name}) + else(${var}) + message(STATUS " Disabling ${name} support.") + list(APPEND _gr_disabled_components ${name}) + endif(${var}) + message(STATUS " Override with -D${var}=ON/OFF") + + #make components lists into global variables + set(_gr_enabled_components ${_gr_enabled_components} CACHE INTERNAL "" FORCE) + set(_gr_disabled_components ${_gr_disabled_components} CACHE INTERNAL "" FORCE) +endfunction(GR_REGISTER_COMPONENT) + +######################################################################## +# Print the registered component summary +######################################################################## +function(GR_PRINT_COMPONENT_SUMMARY) + message(STATUS "") + message(STATUS "######################################################") + message(STATUS "# gr-osmosdr enabled components ") + message(STATUS "######################################################") + foreach(comp ${_gr_enabled_components}) + message(STATUS " * ${comp}") + endforeach(comp) + + message(STATUS "") + message(STATUS "######################################################") + message(STATUS "# gr-osmosdr disabled components ") + message(STATUS "######################################################") + foreach(comp ${_gr_disabled_components}) + message(STATUS " * ${comp}") + endforeach(comp) + + message(STATUS "") +endfunction(GR_PRINT_COMPONENT_SUMMARY) diff --git a/cmake/Modules/GrMiscUtils.cmake b/cmake/Modules/GrMiscUtils.cmake new file mode 100644 index 0000000..747eb1a --- /dev/null +++ b/cmake/Modules/GrMiscUtils.cmake @@ -0,0 +1,519 @@ +# Copyright 2010-2011,2014 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE) + return() +endif() +set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE) + +######################################################################## +# Set global variable macro. +# Used for subdirectories to export settings. +# Example: include and library paths. +######################################################################## +function(GR_SET_GLOBAL var) + set(${var} ${ARGN} CACHE INTERNAL "" FORCE) +endfunction(GR_SET_GLOBAL) + +######################################################################## +# Set the pre-processor definition if the condition is true. +# - def the pre-processor definition to set and condition name +######################################################################## +function(GR_ADD_COND_DEF def) + if(${def}) + add_definitions(-D${def}) + endif(${def}) +endfunction(GR_ADD_COND_DEF) + +######################################################################## +# Check for a header and conditionally set a compile define. +# - hdr the relative path to the header file +# - def the pre-processor definition to set +######################################################################## +function(GR_CHECK_HDR_N_DEF hdr def) + include(CheckIncludeFileCXX) + CHECK_INCLUDE_FILE_CXX(${hdr} ${def}) + GR_ADD_COND_DEF(${def}) +endfunction(GR_CHECK_HDR_N_DEF) + +######################################################################## +# Include subdirectory macro. +# Sets the CMake directory variables, +# includes the subdirectory CMakeLists.txt, +# resets the CMake directory variables. +# +# This macro includes subdirectories rather than adding them +# so that the subdirectory can affect variables in the level above. +# This provides a work-around for the lack of convenience libraries. +# This way a subdirectory can append to the list of library sources. +######################################################################## +macro(GR_INCLUDE_SUBDIRECTORY subdir) + #insert the current directories on the front of the list + list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR}) + list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR}) + + #set the current directories to the names of the subdirs + set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}) + set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir}) + + #include the subdirectory CMakeLists to run it + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) + + #reset the value of the current directories + list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR) + list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR) + + #pop the subdir names of the front of the list + list(REMOVE_AT _cmake_source_dirs 0) + list(REMOVE_AT _cmake_binary_dirs 0) +endmacro(GR_INCLUDE_SUBDIRECTORY) + +######################################################################## +# Check if a compiler flag works and conditionally set a compile define. +# - flag the compiler flag to check for +# - have the variable to set with result +######################################################################## +macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(${flag} ${have}) + if(${have}) + add_definitions(${flag}) + endif(${have}) +endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE) + +######################################################################## +# Generates the .la libtool file +# This appears to generate libtool files that cannot be used by auto*. +# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest]) +# Notice: there is not COMPONENT option, these will not get distributed. +######################################################################## +function(GR_LIBTOOL) + if(NOT DEFINED GENERATE_LIBTOOL) + set(GENERATE_LIBTOOL OFF) #disabled by default + endif() + + if(GENERATE_LIBTOOL) + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN}) + + find_program(LIBTOOL libtool) + if(LIBTOOL) + include(CMakeMacroLibtoolFile) + CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION}) + endif(LIBTOOL) + endif(GENERATE_LIBTOOL) + +endfunction(GR_LIBTOOL) + +######################################################################## +# Do standard things to the library target +# - set target properties +# - make install rules +# Also handle gnuradio custom naming conventions w/ extras mode. +######################################################################## +function(GR_LIBRARY_FOO target) + #parse the arguments for component names + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN}) + + #set additional target properties + set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER}) + + #install the generated files like so... + install(TARGETS ${target} + LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file + ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file + RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file + ) + + #extras mode enabled automatically on linux + if(NOT DEFINED LIBRARY_EXTRAS) + set(LIBRARY_EXTRAS ${LINUX}) + endif() + + #special extras mode to enable alternative naming conventions + if(LIBRARY_EXTRAS) + + #create .la file before changing props + GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR}) + + #give the library a special name with ultra-zero soversion + set_target_properties(${target} PROPERTIES OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0") + set(target_name lib${target}-${LIBVER}.so.0.0.0) + + #custom command to generate symlinks + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so + COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0 + COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install + ) + + #and install the extra symlinks + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so + ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0 + DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} + ) + + endif(LIBRARY_EXTRAS) +endfunction(GR_LIBRARY_FOO) + +######################################################################## +# Create a dummy custom command that depends on other targets. +# Usage: +# GR_GEN_TARGET_DEPS(unique_name target_deps <target1> <target2> ...) +# ADD_CUSTOM_COMMAND(<the usual args> ${target_deps}) +# +# Custom command cant depend on targets, but can depend on executables, +# and executables can depend on targets. So this is the process: +######################################################################## +function(GR_GEN_TARGET_DEPS name var) + file( + WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in + "int main(void){return 0;}\n" + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp + ) + add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp) + if(ARGN) + add_dependencies(${name} ${ARGN}) + endif(ARGN) + + if(CMAKE_CROSSCOMPILING) + set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross + else() + set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE) + endif() +endfunction(GR_GEN_TARGET_DEPS) + +######################################################################## +# Control use of gr_logger +# Usage: +# GR_LOGGING() +# +# Will set ENABLE_GR_LOG to 1 by default. +# Can manually set with -DENABLE_GR_LOG=0|1 +######################################################################## +function(GR_LOGGING) + find_package(Log4cpp) + + OPTION(ENABLE_GR_LOG "Use gr_logger" ON) + if(ENABLE_GR_LOG) + # If gr_logger is enabled, make it usable + add_definitions( -DENABLE_GR_LOG ) + + # also test LOG4CPP; if we have it, use this version of the logger + # otherwise, default to the stdout/stderr model. + if(LOG4CPP_FOUND) + SET(HAVE_LOG4CPP True CACHE INTERNAL "" FORCE) + add_definitions( -DHAVE_LOG4CPP ) + else(not LOG4CPP_FOUND) + SET(HAVE_LOG4CPP False CACHE INTERNAL "" FORCE) + SET(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE) + SET(LOG4CPP_LIBRARY_DIRS "" CACHE INTERNAL "" FORCE) + SET(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE) + endif(LOG4CPP_FOUND) + + SET(ENABLE_GR_LOG ${ENABLE_GR_LOG} CACHE INTERNAL "" FORCE) + + else(ENABLE_GR_LOG) + SET(HAVE_LOG4CPP False CACHE INTERNAL "" FORCE) + SET(LOG4CPP_INCLUDE_DIRS "" CACHE INTERNAL "" FORCE) + SET(LOG4CPP_LIBRARY_DIRS "" CACHE INTERNAL "" FORCE) + SET(LOG4CPP_LIBRARIES "" CACHE INTERNAL "" FORCE) + endif(ENABLE_GR_LOG) + + message(STATUS "ENABLE_GR_LOG set to ${ENABLE_GR_LOG}.") + message(STATUS "HAVE_LOG4CPP set to ${HAVE_LOG4CPP}.") + message(STATUS "LOG4CPP_LIBRARIES set to ${LOG4CPP_LIBRARIES}.") + +endfunction(GR_LOGGING) + +######################################################################## +# Run GRCC to compile .grc files into .py files. +# +# Usage: GRCC(filename, directory) +# - filenames: List of file name of .grc file +# - directory: directory of built .py file - usually in +# ${CMAKE_CURRENT_BINARY_DIR} +# - Sets PYFILES: output converted GRC file names to Python files. +######################################################################## +function(GRCC) + # Extract directory from list of args, remove it for the list of filenames. + list(GET ARGV -1 directory) + list(REMOVE_AT ARGV -1) + set(filenames ${ARGV}) + file(MAKE_DIRECTORY ${directory}) + + SET(GRCC_COMMAND ${CMAKE_SOURCE_DIR}/gr-utils/python/grcc) + + # GRCC uses some stuff in grc and gnuradio-runtime, so we force + # the known paths here + list(APPEND PYTHONPATHS + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/gnuradio-runtime/python + ${CMAKE_SOURCE_DIR}/gnuradio-runtime/lib/swig + ${CMAKE_BINARY_DIR}/gnuradio-runtime/lib/swig + ) + + if(WIN32) + #SWIG generates the python library files into a subdirectory. + #Therefore, we must append this subdirectory into PYTHONPATH. + #Only do this for the python directories matching the following: + foreach(pydir ${PYTHONPATHS}) + get_filename_component(name ${pydir} NAME) + if(name MATCHES "^(swig|lib|src)$") + list(APPEND PYTHONPATHS ${pydir}/${CMAKE_BUILD_TYPE}) + endif() + endforeach(pydir) + endif(WIN32) + + file(TO_NATIVE_PATH "${PYTHONPATHS}" pypath) + + if(UNIX) + list(APPEND pypath "$PYTHONPATH") + string(REPLACE ";" ":" pypath "${pypath}") + set(ENV{PYTHONPATH} ${pypath}) + endif(UNIX) + + if(WIN32) + list(APPEND pypath "%PYTHONPATH%") + string(REPLACE ";" "\\;" pypath "${pypath}") + #list(APPEND environs "PYTHONPATH=${pypath}") + set(ENV{PYTHONPATH} ${pypath}) + endif(WIN32) + + foreach(f ${filenames}) + execute_process( + COMMAND ${GRCC_COMMAND} -d ${directory} ${f} + ) + string(REPLACE ".grc" ".py" pyfile "${f}") + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" pyfile "${pyfile}") + list(APPEND pyfiles ${pyfile}) + endforeach(f) + + set(PYFILES ${pyfiles} PARENT_SCOPE) +endfunction(GRCC) + +######################################################################## +# Check if HAVE_PTHREAD_SETSCHEDPARAM and HAVE_SCHED_SETSCHEDULER +# should be defined +######################################################################## +macro(GR_CHECK_LINUX_SCHED_AVAIL) +set(CMAKE_REQUIRED_LIBRARIES -lpthread) + CHECK_CXX_SOURCE_COMPILES(" + #include <pthread.h> + int main(){ + pthread_t pthread; + pthread_setschedparam(pthread, 0, 0); + return 0; + } " HAVE_PTHREAD_SETSCHEDPARAM + ) + GR_ADD_COND_DEF(HAVE_PTHREAD_SETSCHEDPARAM) + + CHECK_CXX_SOURCE_COMPILES(" + #include <sched.h> + int main(){ + pid_t pid; + sched_setscheduler(pid, 0, 0); + return 0; + } " HAVE_SCHED_SETSCHEDULER + ) + GR_ADD_COND_DEF(HAVE_SCHED_SETSCHEDULER) +endmacro(GR_CHECK_LINUX_SCHED_AVAIL) + +######################################################################## +# Macros to generate source and header files from template +######################################################################## +macro(GR_EXPAND_X_H component root) + + include(GrPython) + + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py +"#!${PYTHON_EXECUTABLE} + +import sys, os, re +sys.path.append('${GR_RUNTIME_PYTHONPATH}') +os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}' +os.chdir('${CMAKE_CURRENT_BINARY_DIR}') + +if __name__ == '__main__': + import build_utils + root, inp = sys.argv[1:3] + for sig in sys.argv[3:]: + name = re.sub ('X+', sig, root) + d = build_utils.standard_dict2(name, sig, '${component}') + build_utils.expand_template(d, inp) +") + + #make a list of all the generated headers + unset(expanded_files_h) + foreach(sig ${ARGN}) + string(REGEX REPLACE "X+" ${sig} name ${root}) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h) + endforeach(sig) + unset(name) + + #create a command to generate the headers + add_custom_command( + OUTPUT ${expanded_files_h} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.h.t ${ARGN} + ) + + #install rules for the generated headers + list(APPEND generated_includes ${expanded_files_h}) + +endmacro(GR_EXPAND_X_H) + +macro(GR_EXPAND_X_CC_H component root) + + include(GrPython) + + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py +"#!${PYTHON_EXECUTABLE} + +import sys, os, re +sys.path.append('${GR_RUNTIME_PYTHONPATH}') +os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}' +os.chdir('${CMAKE_CURRENT_BINARY_DIR}') + +if __name__ == '__main__': + import build_utils + root, inp = sys.argv[1:3] + for sig in sys.argv[3:]: + name = re.sub ('X+', sig, root) + d = build_utils.standard_impl_dict2(name, sig, '${component}') + build_utils.expand_template(d, inp) +") + + #make a list of all the generated files + unset(expanded_files_cc) + unset(expanded_files_h) + foreach(sig ${ARGN}) + string(REGEX REPLACE "X+" ${sig} name ${root}) + list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h) + endforeach(sig) + unset(name) + + #create a command to generate the source files + add_custom_command( + OUTPUT ${expanded_files_cc} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.cc.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.cc.t ${ARGN} + ) + + #create a command to generate the header files + add_custom_command( + OUTPUT ${expanded_files_h} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.h.t ${ARGN} + ) + + #make source files depends on headers to force generation + set_source_files_properties(${expanded_files_cc} + PROPERTIES OBJECT_DEPENDS "${expanded_files_h}" + ) + + #install rules for the generated files + list(APPEND generated_sources ${expanded_files_cc}) + list(APPEND generated_headers ${expanded_files_h}) + +endmacro(GR_EXPAND_X_CC_H) + +macro(GR_EXPAND_X_CC_H_IMPL component root) + + include(GrPython) + + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py +"#!${PYTHON_EXECUTABLE} + +import sys, os, re +sys.path.append('${GR_RUNTIME_PYTHONPATH}') +os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}' +os.chdir('${CMAKE_CURRENT_BINARY_DIR}') + +if __name__ == '__main__': + import build_utils + root, inp = sys.argv[1:3] + for sig in sys.argv[3:]: + name = re.sub ('X+', sig, root) + d = build_utils.standard_dict(name, sig, '${component}') + build_utils.expand_template(d, inp, '_impl') +") + + #make a list of all the generated files + unset(expanded_files_cc_impl) + unset(expanded_files_h_impl) + unset(expanded_files_h) + foreach(sig ${ARGN}) + string(REGEX REPLACE "X+" ${sig} name ${root}) + list(APPEND expanded_files_cc_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.cc) + list(APPEND expanded_files_h_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.h) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/../include/gnuradio/${component}/${name}.h) + endforeach(sig) + unset(name) + + #create a command to generate the _impl.cc files + add_custom_command( + OUTPUT ${expanded_files_cc_impl} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.cc.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}_impl.cc.t ${ARGN} + ) + + #create a command to generate the _impl.h files + add_custom_command( + OUTPUT ${expanded_files_h_impl} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}_impl.h.t ${ARGN} + ) + + #make _impl.cc source files depend on _impl.h to force generation + set_source_files_properties(${expanded_files_cc_impl} + PROPERTIES OBJECT_DEPENDS "${expanded_files_h_impl}" + ) + + #make _impl.h source files depend on headers to force generation + set_source_files_properties(${expanded_files_h_impl} + PROPERTIES OBJECT_DEPENDS "${expanded_files_h}" + ) + + #install rules for the generated files + list(APPEND generated_sources ${expanded_files_cc_impl}) + list(APPEND generated_headers ${expanded_files_h_impl}) + +endmacro(GR_EXPAND_X_CC_H_IMPL) diff --git a/cmake/Modules/GrPlatform.cmake b/cmake/Modules/GrPlatform.cmake new file mode 100644 index 0000000..fbbea5f --- /dev/null +++ b/cmake/Modules/GrPlatform.cmake @@ -0,0 +1,54 @@ +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE) + return() +endif() +set(__INCLUDED_GR_PLATFORM_CMAKE TRUE) + +######################################################################## +# Setup additional defines for OS types +######################################################################## +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(LINUX TRUE) +endif() + +if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/debian_version") + set(DEBIAN TRUE) +endif() + +if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/redhat-release") + set(REDHAT TRUE) +endif() + +if(NOT CMAKE_CROSSCOMPILING AND LINUX AND EXISTS "/etc/slackware-version") + set(SLACKWARE TRUE) +endif() + +######################################################################## +# when the library suffix should be 64 (applies to redhat linux family) +######################################################################## +if (REDHAT OR SLACKWARE) + set(LIB64_CONVENTION TRUE) +endif() + +if(NOT DEFINED LIB_SUFFIX AND LIB64_CONVENTION AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$") + set(LIB_SUFFIX 64) +endif() +set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix") diff --git a/cmake/Modules/GrPython.cmake b/cmake/Modules/GrPython.cmake new file mode 100644 index 0000000..395faff --- /dev/null +++ b/cmake/Modules/GrPython.cmake @@ -0,0 +1,242 @@ +# Copyright 2010-2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_GR_PYTHON_CMAKE) + return() +endif() +set(__INCLUDED_GR_PYTHON_CMAKE TRUE) + +######################################################################## +# Setup the python interpreter: +# This allows the user to specify a specific interpreter, +# or finds the interpreter via the built-in cmake module. +######################################################################## +#this allows the user to override PYTHON_EXECUTABLE +if(PYTHON_EXECUTABLE) + + set(PYTHONINTERP_FOUND TRUE) + +#otherwise if not set, try to automatically find it +else(PYTHON_EXECUTABLE) + + #use the built-in find script + find_package(PythonInterp 2) + + #and if that fails use the find program routine + if(NOT PYTHONINTERP_FOUND) + find_program(PYTHON_EXECUTABLE NAMES python python2 python2.7 python2.6 python2.5) + if(PYTHON_EXECUTABLE) + set(PYTHONINTERP_FOUND TRUE) + endif(PYTHON_EXECUTABLE) + endif(NOT PYTHONINTERP_FOUND) + +endif(PYTHON_EXECUTABLE) + +if (CMAKE_CROSSCOMPILING) + set(QA_PYTHON_EXECUTABLE "/usr/bin/python") +else (CMAKE_CROSSCOMPILING) + set(QA_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) +endif(CMAKE_CROSSCOMPILING) + +#make the path to the executable appear in the cmake gui +set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") +set(QA_PYTHON_EXECUTABLE ${QA_PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter for QA tests") + +#make sure we can use -B with python (introduced in 2.6) +if(PYTHON_EXECUTABLE) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -B -c "" + OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT + ) + if(PYTHON_HAS_DASH_B_RESULT EQUAL 0) + set(PYTHON_DASH_B "-B") + endif() +endif(PYTHON_EXECUTABLE) + +######################################################################## +# Check for the existence of a python module: +# - desc a string description of the check +# - mod the name of the module to import +# - cmd an additional command to run +# - have the result variable to set +######################################################################## +macro(GR_PYTHON_CHECK_MODULE desc mod cmd have) + message(STATUS "") + message(STATUS "Python checking for ${desc}") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c " +######################################### +try: + import ${mod} + assert ${cmd} +except ImportError, AssertionError: exit(-1) +except: pass +#########################################" + RESULT_VARIABLE ${have} + ) + if(${have} EQUAL 0) + message(STATUS "Python checking for ${desc} - found") + set(${have} TRUE) + else(${have} EQUAL 0) + message(STATUS "Python checking for ${desc} - not found") + set(${have} FALSE) + endif(${have} EQUAL 0) +endmacro(GR_PYTHON_CHECK_MODULE) + +######################################################################## +# Sets the python installation directory GR_PYTHON_DIR +######################################################################## +if(NOT DEFINED GR_PYTHON_DIR) +execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " +from distutils import sysconfig +print sysconfig.get_python_lib(plat_specific=True, prefix='') +" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE +) +endif() +file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR) + +######################################################################## +# Create an always-built target with a unique name +# Usage: GR_UNIQUE_TARGET(<description> <dependencies list>) +######################################################################## +function(GR_UNIQUE_TARGET desc) + file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib +unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5] +print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))" + OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE) + add_custom_target(${_target} ALL DEPENDS ${ARGN}) +endfunction(GR_UNIQUE_TARGET) + +######################################################################## +# Install python sources (also builds and installs byte-compiled python) +######################################################################## +function(GR_PYTHON_INSTALL) + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN}) + + #################################################################### + if(GR_PYTHON_INSTALL_FILES) + #################################################################### + install(${ARGN}) #installs regular python files + + #create a list of all generated files + unset(pysrcfiles) + unset(pycfiles) + unset(pyofiles) + foreach(pyfile ${GR_PYTHON_INSTALL_FILES}) + get_filename_component(pyfile ${pyfile} ABSOLUTE) + list(APPEND pysrcfiles ${pyfile}) + + #determine if this file is in the source or binary directory + file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile}) + string(LENGTH "${source_rel_path}" source_rel_path_len) + file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile}) + string(LENGTH "${binary_rel_path}" binary_rel_path_len) + + #and set the generated path appropriately + if(${source_rel_path_len} GREATER ${binary_rel_path_len}) + set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path}) + else() + set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path}) + endif() + list(APPEND pycfiles ${pygenfile}c) + list(APPEND pyofiles ${pygenfile}o) + + #ensure generation path exists + get_filename_component(pygen_path ${pygenfile} PATH) + file(MAKE_DIRECTORY ${pygen_path}) + + endforeach(pyfile) + + #the command to generate the pyc files + add_custom_command( + DEPENDS ${pysrcfiles} OUTPUT ${pycfiles} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles} + ) + + #the command to generate the pyo files + add_custom_command( + DEPENDS ${pysrcfiles} OUTPUT ${pyofiles} + COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles} + ) + + #create install rule and add generated files to target list + set(python_install_gen_targets ${pycfiles} ${pyofiles}) + install(FILES ${python_install_gen_targets} + DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} + COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} + ) + + + #################################################################### + elseif(GR_PYTHON_INSTALL_PROGRAMS) + #################################################################### + file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native) + + if (CMAKE_CROSSCOMPILING) + set(pyexe_native "/usr/bin/env python") + endif() + + foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS}) + get_filename_component(pyfile_name ${pyfile} NAME) + get_filename_component(pyfile ${pyfile} ABSOLUTE) + string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe") + list(APPEND python_install_gen_targets ${pyexefile}) + + get_filename_component(pyexefile_path ${pyexefile} PATH) + file(MAKE_DIRECTORY ${pyexefile_path}) + + add_custom_command( + OUTPUT ${pyexefile} DEPENDS ${pyfile} + COMMAND ${PYTHON_EXECUTABLE} -c + "open('${pyexefile}','w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())" + COMMENT "Shebangin ${pyfile_name}" + VERBATIM + ) + + #on windows, python files need an extension to execute + get_filename_component(pyfile_ext ${pyfile} EXT) + if(WIN32 AND NOT pyfile_ext) + set(pyfile_name "${pyfile_name}.py") + endif() + + install(PROGRAMS ${pyexefile} RENAME ${pyfile_name} + DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} + COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} + ) + endforeach(pyfile) + + endif() + + GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets}) + +endfunction(GR_PYTHON_INSTALL) + +######################################################################## +# Write the python helper script that generates byte code files +######################################################################## +file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py " +import sys, py_compile +files = sys.argv[1:] +srcs, gens = files[:len(files)/2], files[len(files)/2:] +for src, gen in zip(srcs, gens): + py_compile.compile(file=src, cfile=gen, doraise=True) +") diff --git a/cmake/Modules/GrTest.cmake b/cmake/Modules/GrTest.cmake new file mode 100644 index 0000000..62caab4 --- /dev/null +++ b/cmake/Modules/GrTest.cmake @@ -0,0 +1,143 @@ +# Copyright 2010-2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_GR_TEST_CMAKE) + return() +endif() +set(__INCLUDED_GR_TEST_CMAKE TRUE) + +######################################################################## +# Add a unit test and setup the environment for a unit test. +# Takes the same arguments as the ADD_TEST function. +# +# Before calling set the following variables: +# GR_TEST_TARGET_DEPS - built targets for the library path +# GR_TEST_LIBRARY_DIRS - directories for the library path +# GR_TEST_PYTHON_DIRS - directories for the python path +# GR_TEST_ENVIRONS - other environment key/value pairs +######################################################################## +function(GR_ADD_TEST test_name) + + #Ensure that the build exe also appears in the PATH. + list(APPEND GR_TEST_TARGET_DEPS ${ARGN}) + + #In the land of windows, all libraries must be in the PATH. + #Since the dependent libraries are not yet installed, + #we must manually set them in the PATH to run tests. + #The following appends the path of a target dependency. + foreach(target ${GR_TEST_TARGET_DEPS}) + get_target_property(location ${target} LOCATION) + if(location) + get_filename_component(path ${location} PATH) + string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path}) + list(APPEND GR_TEST_LIBRARY_DIRS ${path}) + endif(location) + endforeach(target) + + if(WIN32) + #SWIG generates the python library files into a subdirectory. + #Therefore, we must append this subdirectory into PYTHONPATH. + #Only do this for the python directories matching the following: + foreach(pydir ${GR_TEST_PYTHON_DIRS}) + get_filename_component(name ${pydir} NAME) + if(name MATCHES "^(swig|lib|src)$") + list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE}) + endif() + endforeach(pydir) + endif(WIN32) + + file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir) + file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list? + file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list? + + set(environs "VOLK_GENERIC=1" "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}") + list(APPEND environs ${GR_TEST_ENVIRONS}) + + #http://www.cmake.org/pipermail/cmake/2009-May/029464.html + #Replaced this add test + set environs code with the shell script generation. + #Its nicer to be able to manually run the shell script to diagnose problems. + #ADD_TEST(${ARGV}) + #SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}") + + if(UNIX) + set(LD_PATH_VAR "LD_LIBRARY_PATH") + if(APPLE) + set(LD_PATH_VAR "DYLD_LIBRARY_PATH") + endif() + + set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH") + list(APPEND libpath "$${LD_PATH_VAR}") + list(APPEND pypath "$PYTHONPATH") + + #replace list separator with the path separator + string(REPLACE ";" ":" libpath "${libpath}") + string(REPLACE ";" ":" pypath "${pypath}") + list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}" "PYTHONPATH=${pypath}") + + #generate a bat file that sets the environment and runs the test + if (CMAKE_CROSSCOMPILING) + set(SHELL "/bin/sh") + else(CMAKE_CROSSCOMPILING) + find_program(SHELL sh) + endif(CMAKE_CROSSCOMPILING) + set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh) + file(WRITE ${sh_file} "#!${SHELL}\n") + #each line sets an environment variable + foreach(environ ${environs}) + file(APPEND ${sh_file} "export ${environ}\n") + endforeach(environ) + #load the command to run with its arguments + foreach(arg ${ARGN}) + file(APPEND ${sh_file} "${arg} ") + endforeach(arg) + file(APPEND ${sh_file} "\n") + + #make the shell file executable + execute_process(COMMAND chmod +x ${sh_file}) + + add_test(${test_name} ${SHELL} ${sh_file}) + + endif(UNIX) + + if(WIN32) + list(APPEND libpath ${DLL_PATHS} "%PATH%") + list(APPEND pypath "%PYTHONPATH%") + + #replace list separator with the path separator (escaped) + string(REPLACE ";" "\\;" libpath "${libpath}") + string(REPLACE ";" "\\;" pypath "${pypath}") + list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}") + + #generate a bat file that sets the environment and runs the test + set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat) + file(WRITE ${bat_file} "@echo off\n") + #each line sets an environment variable + foreach(environ ${environs}) + file(APPEND ${bat_file} "SET ${environ}\n") + endforeach(environ) + #load the command to run with its arguments + foreach(arg ${ARGN}) + file(APPEND ${bat_file} "${arg} ") + endforeach(arg) + file(APPEND ${bat_file} "\n") + + add_test(${test_name} ${bat_file}) + endif(WIN32) + +endfunction(GR_ADD_TEST) diff --git a/cmake/Modules/GrVersion.cmake b/cmake/Modules/GrVersion.cmake new file mode 100644 index 0000000..bafd0a7 --- /dev/null +++ b/cmake/Modules/GrVersion.cmake @@ -0,0 +1,82 @@ +# Copyright 2011,2013 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_GR_VERSION_CMAKE) + return() +endif() +set(__INCLUDED_GR_VERSION_CMAKE TRUE) + +#eventually, replace version.sh and fill in the variables below +set(MAJOR_VERSION ${VERSION_INFO_MAJOR_VERSION}) +set(API_COMPAT ${VERSION_INFO_API_COMPAT}) +set(MINOR_VERSION ${VERSION_INFO_MINOR_VERSION}) +set(MAINT_VERSION ${VERSION_INFO_MAINT_VERSION}) + +######################################################################## +# Extract the version string from git describe. +######################################################################## +find_package(Git) + +if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) + message(STATUS "Extracting version information from git describe...") + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --always --abbrev=8 --long + OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) +else() + set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}.x-xxx-xunknown") +endif() + +######################################################################## +# Use the logic below to set the version constants +######################################################################## +if("${MINOR_VERSION}" STREQUAL "git") + # VERSION: 3.3git-xxx-gxxxxxxxx + # DOCVER: 3.3git + # LIBVER: 3.3git + set(VERSION "${GIT_DESCRIBE}") + set(DOCVER "${MAJOR_VERSION}.${API_COMPAT}${MINOR_VERSION}") + set(LIBVER "${MAJOR_VERSION}.${API_COMPAT}${MINOR_VERSION}") + set(RC_MINOR_VERSION "0") + set(RC_MAINT_VERSION "0") +elseif("${MAINT_VERSION}" STREQUAL "git") + # VERSION: 3.3.1git-xxx-gxxxxxxxx + # DOCVER: 3.3.1git + # LIBVER: 3.3.1git + set(VERSION "${GIT_DESCRIBE}") + set(DOCVER "${MAJOR_VERSION}.${API_COMPAT}.${MINOR_VERSION}${MAINT_VERSION}") + set(LIBVER "${MAJOR_VERSION}.${API_COMPAT}.${MINOR_VERSION}${MAINT_VERSION}") + math(EXPR RC_MINOR_VERSION "${MINOR_VERSION} - 1") + set(RC_MAINT_VERSION "0") +else() + # This is a numbered release. + # VERSION: 3.3.1{.x} + # DOCVER: 3.3.1{.x} + # LIBVER: 3.3.1{.x} + if("${MAINT_VERSION}" STREQUAL "0") + set(VERSION "${MAJOR_VERSION}.${API_COMPAT}.${MINOR_VERSION}") + else() + set(VERSION "${MAJOR_VERSION}.${API_COMPAT}.${MINOR_VERSION}.${MAINT_VERSION}") + endif() + set(DOCVER "${VERSION}") + set(LIBVER "${VERSION}") + set(RC_MINOR_VERSION ${MINOR_VERSION}) + set(RC_MAINT_VERSION ${MAINT_VERSION}) +endif() diff --git a/cmake/Modules/OsmoSDRMiscUtils.cmake b/cmake/Modules/OsmoSDRMiscUtils.cmake new file mode 100644 index 0000000..21c6351 --- /dev/null +++ b/cmake/Modules/OsmoSDRMiscUtils.cmake @@ -0,0 +1,132 @@ +# Copyright 2010-2011,2014 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +if(DEFINED __INCLUDED_OSMOSDR_MISC_UTILS_CMAKE) + return() +endif() +set(__INCLUDED_OSMOSDR_MISC_UTILS_CMAKE TRUE) + +######################################################################## +# This macro includes subdirectories rather than adding them +# so that the subdirectory can affect variables in the level above. +# This provides a work-around for the lack of convenience libraries. +# This way a subdirectory can append to the list of library sources. +######################################################################## +macro(GR_INCLUDE_SUBDIRECTORY subdir) + #insert the current directories on the front of the list + list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR}) + list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR}) + + #set the current directories to the names of the subdirs + set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}) + set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir}) + + #include the subdirectory CMakeLists to run it + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) + + #reset the value of the current directories + list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR) + list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR) + + #pop the subdir names of the front of the list + list(REMOVE_AT _cmake_source_dirs 0) + list(REMOVE_AT _cmake_binary_dirs 0) +endmacro(GR_INCLUDE_SUBDIRECTORY) + + +######################################################################## +# Generates the .la libtool file +# This appears to generate libtool files that cannot be used by auto*. +# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest]) +# Notice: there is not COMPONENT option, these will not get distributed. +######################################################################## +function(GR_LIBTOOL) + if(NOT DEFINED GENERATE_LIBTOOL) + set(GENERATE_LIBTOOL OFF) #disabled by default + endif() + + if(GENERATE_LIBTOOL) + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN}) + + find_program(LIBTOOL libtool) + if(LIBTOOL) + include(CMakeMacroLibtoolFile) + CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION}) + endif(LIBTOOL) + endif(GENERATE_LIBTOOL) + +endfunction(GR_LIBTOOL) + +######################################################################## +# Do standard things to the library target +# - set target properties +# - make install rules +# Also handle gnuradio custom naming conventions w/ extras mode. +######################################################################## +function(GR_LIBRARY_FOO_V2 target) + #parse the arguments for component names + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN}) + + #set additional target properties + set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER}) + + #install the generated files like so... + install(TARGETS ${target} + LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file + ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file + RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file + ) + + #extras mode enabled automatically on linux + if(NOT DEFINED LIBRARY_EXTRAS) + set(LIBRARY_EXTRAS ${LINUX}) + endif() + + #special extras mode to enable alternative naming conventions + if(LIBRARY_EXTRAS) + + #create .la file before changing props + GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR}) + + #give the library a special name with ultra-zero soversion + set_target_properties(${target} PROPERTIES OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0") + set(target_name lib${target}-${LIBVER}.so.0.0.0) + + #custom command to generate symlinks + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so + COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0 + COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install + ) + + #and install the extra symlinks + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so + ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0 + DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} + ) + + endif(LIBRARY_EXTRAS) +endfunction(GR_LIBRARY_FOO_V2) diff --git a/cmake/Modules/osmosdrConfig.cmake b/cmake/Modules/osmosdrConfig.cmake new file mode 100644 index 0000000..a3b341a --- /dev/null +++ b/cmake/Modules/osmosdrConfig.cmake @@ -0,0 +1,31 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_OSMOSDR osmosdr) + +FIND_PATH( + OSMOSDR_INCLUDE_DIRS + NAMES osmosdr/api.h + HINTS $ENV{OSMOSDR_DIR}/include + ${PC_OSMOSDR_INCLUDEDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/include + /usr/local/include + /usr/include +) + +FIND_LIBRARY( + OSMOSDR_LIBRARIES + NAMES gnuradio-osmosdr + HINTS $ENV{OSMOSDR_DIR}/lib + ${PC_OSMOSDR_LIBDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + ) + +include("${CMAKE_CURRENT_LIST_DIR}/osmosdrTarget.cmake") + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OSMOSDR DEFAULT_MSG OSMOSDR_LIBRARIES OSMOSDR_INCLUDE_DIRS) +MARK_AS_ADVANCED(OSMOSDR_LIBRARIES OSMOSDR_INCLUDE_DIRS) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index aa620b4..a50dbf8 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,23 +1,29 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file was generated by gr_modtool, a tool from the GNU Radio framework +# This file is a part of gr-osmosdr # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## +# Setup dependencies +######################################################################## +find_package(Doxygen) + +######################################################################## # Begin conditional configuration ######################################################################## if(ENABLE_DOXYGEN) diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in index db80050..ab27c33 100644 --- a/docs/doxygen/Doxyfile.in +++ b/docs/doxygen/Doxyfile.in @@ -28,7 +28,7 @@ DOXYFILE_ENCODING = UTF-8 # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. -PROJECT_NAME = "GNU Radio's TEST Package" +PROJECT_NAME = "GNU Radio's OSMOSDR Package" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or @@ -654,8 +654,8 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = "@top_srcdir@" \ - "@top_builddir@" +INPUT = @top_srcdir@ \ + @top_builddir@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -790,7 +790,7 @@ INPUT_FILTER = # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = *.py="@top_srcdir@"/doc/doxygen/other/doxypy.py +FILTER_PATTERNS = *.py=@top_srcdir@/doc/doxygen/other/doxypy.py # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source diff --git a/docs/doxygen/Doxyfile.swig_doc.in b/docs/doxygen/Doxyfile.swig_doc.in index cbe06d6..33bc2af 100644 --- a/docs/doxygen/Doxyfile.swig_doc.in +++ b/docs/doxygen/Doxyfile.swig_doc.in @@ -54,7 +54,7 @@ PROJECT_LOGO = # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. -OUTPUT_DIRECTORY = "@OUTPUT_DIRECTORY@" +OUTPUT_DIRECTORY = @OUTPUT_DIRECTORY@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox index 174edeb..03f00c0 100644 --- a/docs/doxygen/other/group_defs.dox +++ b/docs/doxygen/other/group_defs.dox @@ -1,6 +1,6 @@ /*! - * \defgroup block GNU Radio TEST C++ Signal Processing Blocks - * \brief All C++ blocks that can be used from the TEST GNU Radio + * \defgroup block GNU Radio OSMOSDR C++ Signal Processing Blocks + * \brief All C++ blocks that can be used from the OSMOSDR GNU Radio * module are listed here or in the subcategories below. * */ diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index 07b5bc2..55cd548 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -1,8 +1,8 @@ /*! \mainpage -Welcome to the GNU Radio TEST Block +Welcome to the GNU Radio OSMOSDR Block -This is the intro page for the Doxygen manual generated for the TEST +This is the intro page for the Doxygen manual generated for the OSMOSDR block (docs/doxygen/other/main_page.dox). Edit it to add more detailed documentation about the new GNU Radio modules contained in this project. diff --git a/gnuradio-osmosdr.pc.in b/gnuradio-osmosdr.pc.in new file mode 100644 index 0000000..5f1ae69 --- /dev/null +++ b/gnuradio-osmosdr.pc.in @@ -0,0 +1,15 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/@GR_LIBRARY_DIR@ +includedir=${prefix}/@GR_INCLUDE_DIR@ + +Name: @CPACK_PACKAGE_NAME@ +Description: @CPACK_PACKAGE_DESCRIPTION_SUMMARY@ +URL: http://sdr.osmocom.org/trac/wiki/GrOsmoSDR +Version: @CPACK_PACKAGE_VERSION@ +Requires: gnuradio-runtime gnuradio-blocks +Requires.private: @GR_OSMOSDR_PC_REQUIRES@ +Conflicts: +Cflags: -I${includedir} @GR_OSMOSDR_PC_CFLAGS@ +Libs: -L${libdir} -lgnuradio-osmosdr +Libs.private: @GR_OSMOSDR_PC_LIBS@ diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 3bb52f8..714d88c 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -1,24 +1,24 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## -# Rules for generating the source and sink yml wrappers +# Rules for generating the source and sink xml wrappers ######################################################################## include(GrPython) diff --git a/grc/gen_osmosdr_blocks.py b/grc/gen_osmosdr_blocks.py index 4cca82f..840320a 100644 --- a/grc/gen_osmosdr_blocks.py +++ b/grc/gen_osmosdr_blocks.py @@ -122,11 +122,11 @@ templates: ${'%'} if context.get('nchan')() > ${n}: self.${'$'}{id}.set_center_freq(${'$'}{${'freq' + str(n)}}, ${n}) self.${'$'}{id}.set_freq_corr(${'$'}{${'corr' + str(n)}}, ${n}) - % if sourk == 'source': + ${'%'} if context.get('sourk') == 'source': self.${'$'}{id}.set_dc_offset_mode(${'$'}{${'dc_offset_mode' + str(n)}}, ${n}) self.${'$'}{id}.set_iq_balance_mode(${'$'}{${'iq_balance_mode' + str(n)}}, ${n}) self.${'$'}{id}.set_gain_mode(${'$'}{${'gain_mode' + str(n)}}, ${n}) - % endif + ${'%'} endif self.${'$'}{id}.set_gain(${'$'}{${'gain' + str(n)}}, ${n}) self.${'$'}{id}.set_if_gain(${'$'}{${'if_gain' + str(n)}}, ${n}) self.${'$'}{id}.set_bb_gain(${'$'}{${'bb_gain' + str(n)}}, ${n}) @@ -157,8 +157,10 @@ documentation: |- While primarily being developed for the OsmoSDR hardware, this block as well supports: % if sourk == 'source': + * sysmocom OsmoSDR Devices through libosmosdr * RTL2832U based DVB-T dongles through librtlsdr * RTL-TCP spectrum server (see librtlsdr project) + * MSi2500 based DVB-T dongles through libmirisdr * SDRplay RSP devices through SDRplay library * gnuradio .cfile input through libgnuradio-blocks * RFSPACE SDR-IQ, SDR-IP, NetSDR (incl. X2 option) @@ -171,8 +173,7 @@ documentation: |- * Great Scott Gadgets HackRF through libhackrf * Nuand LLC bladeRF through libbladeRF library * Ettus USRP Devices through Ettus UHD library - * Fairwaves XTRX through libxtrx - * Fairwaves UmTRX through Fairwaves' module for UHD + * Fairwaves UmTRX through Fairwaves' fork of UHD * Red Pitaya SDR transceiver (http://bazaar.redpitaya.com) * FreeSRP through libfreesrp library @@ -191,11 +192,13 @@ documentation: |- Lines ending with ... mean it's possible to bind devices together by specifying multiple device arguments separated with a space. % if sourk == 'source': + miri=0[,buffers=32] ... rtl=serial_number ... rtl=0[,rtl_xtal=28.8e6][,tuner_xtal=28.8e6] ... rtl=1[,buffers=32][,buflen=N*512] ... rtl=2[,direct_samp=0|1|2][,offset_tune=0|1][,bias=0|1] ... rtl_tcp=127.0.0.1:1234[,psize=16384][,direct_samp=0|1|2][,offset_tune=0|1][,bias=0|1] ... + osmosdr=0[,buffers=32][,buflen=N*512] ... file='/path/to/your file',rate=1e6[,freq=100e6][,repeat=true][,throttle=true] ... netsdr=127.0.0.1[:50000][,nchan=2] sdr-ip=127.0.0.1[:50000] @@ -211,7 +214,6 @@ documentation: |- hackrf=0[,buffers=32][,bias=0|1][,bias_tx=0|1] bladerf=0[,tamer=internal|external|external_1pps][,smb=25e6] uhd[,serial=...][,lo_offset=0][,mcr=52e6][,nchan=2][,subdev='\\\\'B:0 A:0\\\\''] ... - xtrx Num Channels: Selects the total number of channels in this multi-device configuration. Required when specifying multiple device arguments. diff --git a/include/osmosdr/CMakeLists.txt b/include/osmosdr/CMakeLists.txt index 9d284d6..d185ee6 100644 --- a/include/osmosdr/CMakeLists.txt +++ b/include/osmosdr/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. diff --git a/include/osmosdr/pimpl.h b/include/osmosdr/pimpl.h index 3a99994..e1985b4 100644 --- a/include/osmosdr/pimpl.h +++ b/include/osmosdr/pimpl.h @@ -18,7 +18,7 @@ #ifndef INCLUDED_OSMOSDR_PIMPL_H #define INCLUDED_OSMOSDR_PIMPL_H -#include <memory> +#include <boost/shared_ptr.hpp> /*! \file pimpl.h * "Pimpl idiom" (pointer to implementation idiom). @@ -39,7 +39,7 @@ * \param _name the name of the pimpl class */ #define OSMOSDR_PIMPL_DECL(_name) \ - struct _name; std::shared_ptr<_name> + struct _name; boost::shared_ptr<_name> /*! * Make an instance of a pimpl in a source file. @@ -49,6 +49,6 @@ * \param _args the constructor args for the pimpl */ #define OSMOSDR_PIMPL_MAKE(_name, _args) \ - std::shared_ptr<_name>(new _name _args) + boost::shared_ptr<_name>(new _name _args) #endif /* INCLUDED_OSMOSDR_PIMPL_H */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 1bb8655..d95109b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,32 +1,41 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## # Setup library ######################################################################## -include(GrPlatform) #define LIB_SUFFIX +INCLUDE(GrPlatform) #define LIB_SUFFIX +INCLUDE(GrMiscUtils) +INCLUDE(GrComponent) ######################################################################## -# Setup target +# Helpful Macros ######################################################################## +MACRO(GR_OSMOSDR_APPEND_SRCS) + LIST(APPEND gr_osmosdr_srcs ${ARGV}) +ENDMACRO(GR_OSMOSDR_APPEND_SRCS) -list(APPEND gr_osmosdr_srcs +MACRO(GR_OSMOSDR_APPEND_LIBS) + LIST(APPEND gr_osmosdr_libs ${ARGV}) +ENDMACRO(GR_OSMOSDR_APPEND_LIBS) + +GR_OSMOSDR_APPEND_SRCS( source_impl.cc sink_impl.cc ranges.cc @@ -34,44 +43,28 @@ list(APPEND gr_osmosdr_srcs time_spec.cc ) +set(CMAKE_CXX_STANDARD 11) + #-pthread Adds support for multithreading with the pthreads library. #This option sets flags for both the preprocessor and linker. (man gcc) if(CMAKE_COMPILER_IS_GNUCXX) list(APPEND Boost_LIBRARIES -pthread) endif() -#dirty macro to allow appending from subdirs -#this appends all unnamed implicit macro args! -MACRO (APPEND_LIB_LIST) - SET (gr_osmosdr_libs "${gr_osmosdr_libs};${ARGN}" CACHE INTERNAL "lib list") -ENDMACRO (APPEND_INTERNAL_LIST) - -set(gr_osmosdr_libs "" CACHE INTERNAL "lib that accumulates link targets") - -add_library(gnuradio-osmosdr SHARED) -APPEND_LIB_LIST(${Boost_LIBRARIES} gnuradio::gnuradio-runtime) -target_include_directories(gnuradio-osmosdr - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC ${Boost_INCLUDE_DIRS} - PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include> - PUBLIC $<INSTALL_INTERFACE:include> - ) -set_target_properties(gnuradio-osmosdr PROPERTIES DEFINE_SYMBOL "gnuradio_osmosdr_EXPORTS") - -if(APPLE) - set_target_properties(gnuradio-osmosdr PROPERTIES - INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" - ) -endif(APPLE) +GR_OSMOSDR_APPEND_LIBS( + ${Boost_LIBRARIES} + gnuradio::gnuradio-blocks + ${GNURADIO_ALL_LIBRARIES} +) ######################################################################## # Setup defines for high resolution timing ######################################################################## -message(STATUS "") -message(STATUS "Configuring high resolution timing...") -include(CheckCXXSourceCompiles) +MESSAGE(STATUS "") +MESSAGE(STATUS "Configuring high resolution timing...") +INCLUDE(CheckCXXSourceCompiles) -set(CMAKE_REQUIRED_LIBRARIES -lrt) +SET(CMAKE_REQUIRED_LIBRARIES -lrt) CHECK_CXX_SOURCE_COMPILES(" #include <ctime> int main(){ @@ -80,9 +73,9 @@ CHECK_CXX_SOURCE_COMPILES(" } " HAVE_CLOCK_GETTIME ) -unset(CMAKE_REQUIRED_LIBRARIES) +UNSET(CMAKE_REQUIRED_LIBRARIES) -include(CheckCXXSourceCompiles) +INCLUDE(CheckCXXSourceCompiles) CHECK_CXX_SOURCE_COMPILES(" #include <mach/mach_time.h> int main(){ @@ -105,22 +98,22 @@ CHECK_CXX_SOURCE_COMPILES(" " HAVE_QUERY_PERFORMANCE_COUNTER ) -if(HAVE_CLOCK_GETTIME) - message(STATUS " High resolution timing supported through clock_gettime.") - set(TIME_SPEC_DEFS HAVE_CLOCK_GETTIME) - APPEND_LIB_LIST( "-lrt") -elseif(HAVE_MACH_ABSOLUTE_TIME) - message(STATUS " High resolution timing supported through mach_absolute_time.") - set(TIME_SPEC_DEFS HAVE_MACH_ABSOLUTE_TIME) -elseif(HAVE_QUERY_PERFORMANCE_COUNTER) - message(STATUS " High resolution timing supported through QueryPerformanceCounter.") - set(TIME_SPEC_DEFS HAVE_QUERY_PERFORMANCE_COUNTER) -else() - message(STATUS " High resolution timing supported through microsec_clock.") - set(TIME_SPEC_DEFS HAVE_MICROSEC_CLOCK) -endif() - -set_source_files_properties( +IF(HAVE_CLOCK_GETTIME) + MESSAGE(STATUS " High resolution timing supported through clock_gettime.") + SET(TIME_SPEC_DEFS HAVE_CLOCK_GETTIME) + GR_OSMOSDR_APPEND_LIBS("-lrt") +ELSEIF(HAVE_MACH_ABSOLUTE_TIME) + MESSAGE(STATUS " High resolution timing supported through mach_absolute_time.") + SET(TIME_SPEC_DEFS HAVE_MACH_ABSOLUTE_TIME) +ELSEIF(HAVE_QUERY_PERFORMANCE_COUNTER) + MESSAGE(STATUS " High resolution timing supported through QueryPerformanceCounter.") + SET(TIME_SPEC_DEFS HAVE_QUERY_PERFORMANCE_COUNTER) +ELSE() + MESSAGE(STATUS " High resolution timing supported through microsec_clock.") + SET(TIME_SPEC_DEFS HAVE_MICROSEC_CLOCK) +ENDIF() + +SET_SOURCE_FILES_PROPERTIES( time_spec.cc PROPERTIES COMPILE_DEFINITIONS "${TIME_SPEC_DEFS}" ) @@ -128,27 +121,27 @@ set_source_files_properties( ######################################################################## # Setup IQBalance component ######################################################################## -GR_REGISTER_COMPONENT("Osmocom IQ Imbalance Correction" ENABLE_IQBALANCE gnuradio-iqbalance_FOUND) +GR_REGISTER_COMPONENT("Osmocom IQ Imbalance Correction" ENABLE_IQBALANCE GNURADIO_IQBALANCE_FOUND) if(ENABLE_IQBALANCE) - add_definitions(-DHAVE_IQBALANCE=1) - target_include_directories(gnuradio-osmosdr PRIVATE ${gnuradio-iqbalance_INCLUDE_DIRS}) - APPEND_LIB_LIST( gnuradio::gnuradio-iqbalance) +add_definitions(-DHAVE_IQBALANCE=1) +include_directories(${GNURADIO_IQBALANCE_INCLUDE_DIRS}) +GR_OSMOSDR_APPEND_LIBS(${GNURADIO_IQBALANCE_LIBRARIES}) endif(ENABLE_IQBALANCE) ######################################################################## -# Setup FCD component +# Setup OsmoSDR component ######################################################################## -GR_REGISTER_COMPONENT("FUNcube Dongle" ENABLE_FCD GNURADIO_FCDPP_FOUND) -if(ENABLE_FCD) - add_subdirectory(fcd) -endif(ENABLE_FCD) +GR_REGISTER_COMPONENT("sysmocom OsmoSDR" ENABLE_OSMOSDR LIBOSMOSDR_FOUND) +if(ENABLE_OSMOSDR) +GR_INCLUDE_SUBDIRECTORY(osmosdr) +endif(ENABLE_OSMOSDR) ######################################################################## # Setup File component ######################################################################## -GR_REGISTER_COMPONENT("IQ File Source & Sink" ENABLE_FILE gnuradio-blocks_FOUND) +GR_REGISTER_COMPONENT("IQ File Source & Sink" ENABLE_FILE GNURADIO_BLOCKS_FOUND) if(ENABLE_FILE) - add_subdirectory(file) +GR_INCLUDE_SUBDIRECTORY(file) endif(ENABLE_FILE) ######################################################################## @@ -156,32 +149,40 @@ endif(ENABLE_FILE) ######################################################################## GR_REGISTER_COMPONENT("Osmocom RTLSDR" ENABLE_RTL LIBRTLSDR_FOUND) if(ENABLE_RTL) - add_subdirectory(rtl) +GR_INCLUDE_SUBDIRECTORY(rtl) endif(ENABLE_RTL) ######################################################################## # Setup RTL_TCP component ######################################################################## -GR_REGISTER_COMPONENT("RTLSDR TCP Client" ENABLE_RTL_TCP gnuradio-blocks_FOUND) +GR_REGISTER_COMPONENT("RTLSDR TCP Client" ENABLE_RTL_TCP GNURADIO_BLOCKS_FOUND) if(ENABLE_RTL_TCP) - add_subdirectory(rtl_tcp) +GR_INCLUDE_SUBDIRECTORY(rtl_tcp) endif(ENABLE_RTL_TCP) ######################################################################## # Setup UHD component ######################################################################## -GR_REGISTER_COMPONENT("Ettus USRP Devices" ENABLE_UHD UHD_FOUND gnuradio-uhd_FOUND) +GR_REGISTER_COMPONENT("Ettus USRP Devices" ENABLE_UHD UHD_FOUND GNURADIO_UHD_FOUND) if(ENABLE_UHD) - add_subdirectory(uhd) +GR_INCLUDE_SUBDIRECTORY(uhd) endif(ENABLE_UHD) ######################################################################## +# Setup MiriSDR component +######################################################################## +GR_REGISTER_COMPONENT("Osmocom MiriSDR" ENABLE_MIRI LIBMIRISDR_FOUND) +if(ENABLE_MIRI) +GR_INCLUDE_SUBDIRECTORY(miri) +endif(ENABLE_MIRI) + +######################################################################## # Setup SDRplay component ######################################################################## if(ENABLE_NONFREE) GR_REGISTER_COMPONENT("SDRplay RSP (NONFREE)" ENABLE_SDRPLAY LIBSDRPLAY_FOUND) if(ENABLE_SDRPLAY) - add_subdirectory(sdrplay) +GR_INCLUDE_SUBDIRECTORY(sdrplay) endif(ENABLE_SDRPLAY) endif(ENABLE_NONFREE) @@ -190,7 +191,7 @@ endif(ENABLE_NONFREE) ######################################################################## GR_REGISTER_COMPONENT("HackRF & rad1o Badge" ENABLE_HACKRF LIBHACKRF_FOUND) if(ENABLE_HACKRF) - add_subdirectory(hackrf) +GR_INCLUDE_SUBDIRECTORY(hackrf) endif(ENABLE_HACKRF) ######################################################################## @@ -198,7 +199,7 @@ endif(ENABLE_HACKRF) ######################################################################## GR_REGISTER_COMPONENT("nuand bladeRF" ENABLE_BLADERF LIBBLADERF_FOUND) if(ENABLE_BLADERF) - add_subdirectory(bladerf) +GR_INCLUDE_SUBDIRECTORY(bladerf) endif(ENABLE_BLADERF) ######################################################################## @@ -206,7 +207,7 @@ endif(ENABLE_BLADERF) ######################################################################## GR_REGISTER_COMPONENT("RFSPACE Receivers" ENABLE_RFSPACE) if(ENABLE_RFSPACE) - add_subdirectory(rfspace) +GR_INCLUDE_SUBDIRECTORY(rfspace) endif(ENABLE_RFSPACE) ######################################################################## @@ -214,23 +215,15 @@ endif(ENABLE_RFSPACE) ######################################################################## GR_REGISTER_COMPONENT("AIRSPY Receiver" ENABLE_AIRSPY LIBAIRSPY_FOUND) if(ENABLE_AIRSPY) - add_subdirectory(airspy) +GR_INCLUDE_SUBDIRECTORY(airspy) endif(ENABLE_AIRSPY) ######################################################################## -# Setup AIRSPYHF component -######################################################################## -GR_REGISTER_COMPONENT("AIRSPY HF+ Receiver" ENABLE_AIRSPYHF LIBAIRSPYHF_FOUND) -if(ENABLE_AIRSPYHF) - add_subdirectory(airspyhf) -endif(ENABLE_AIRSPYHF) - -######################################################################## # Setup SoapySDR component ######################################################################## GR_REGISTER_COMPONENT("SoapySDR support" ENABLE_SOAPY SoapySDR_FOUND) if(ENABLE_SOAPY) - add_subdirectory(soapy) +GR_INCLUDE_SUBDIRECTORY(soapy) endif(ENABLE_SOAPY) ######################################################################## @@ -238,7 +231,7 @@ endif(ENABLE_SOAPY) ######################################################################## GR_REGISTER_COMPONENT("Red Pitaya SDR" ENABLE_REDPITAYA) if(ENABLE_REDPITAYA) - add_subdirectory(redpitaya) +GR_INCLUDE_SUBDIRECTORY(redpitaya) endif(ENABLE_REDPITAYA) ######################################################################## @@ -246,35 +239,37 @@ endif(ENABLE_REDPITAYA) ######################################################################## GR_REGISTER_COMPONENT("FreeSRP support" ENABLE_FREESRP LIBFREESRP_FOUND) if(ENABLE_FREESRP) - add_subdirectory(freesrp) +GR_INCLUDE_SUBDIRECTORY(freesrp) endif(ENABLE_FREESRP) ######################################################################## -# Setup XTRX component -######################################################################## -GR_REGISTER_COMPONENT("XTRX SDR" ENABLE_XTRX LIBXTRX_FOUND) -if(ENABLE_XTRX) - add_subdirectory(xtrx) -endif(ENABLE_XTRX) - -######################################################################## # Setup configuration file ######################################################################## -add_definitions(-DHAVE_CONFIG_H=1) +ADD_DEFINITIONS(-DHAVE_CONFIG_H=1) include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) -configure_file( +CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY) ######################################################################## -# Finalize target +# Set up Windows DLL resource files ######################################################################## -set_target_properties(gnuradio-osmosdr PROPERTIES SOURCES "${gr_osmosdr_srcs}") -target_link_libraries(gnuradio-osmosdr ${gr_osmosdr_libs}) +IF(MSVC) + include(${CMAKE_SOURCE_DIR}/cmake/Modules/GrVersion.cmake) + + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/gnuradio-osmosdr.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-osmosdr.rc + @ONLY) + + GR_OSMOSDR_APPEND_SRCS(${CMAKE_CURRENT_BINARY_DIR}/gnuradio-osmosdr.rc) +ENDIF(MSVC) ######################################################################## -# Install built library files +# Setup libgnuradio-osmosdr library ######################################################################## -include(GrMiscUtils) +ADD_LIBRARY(gnuradio-osmosdr SHARED ${gr_osmosdr_srcs}) +TARGET_LINK_LIBRARIES(gnuradio-osmosdr ${gr_osmosdr_libs}) +SET_TARGET_PROPERTIES(gnuradio-osmosdr PROPERTIES DEFINE_SYMBOL "gnuradio_osmosdr_EXPORTS") GR_LIBRARY_FOO(gnuradio-osmosdr) diff --git a/lib/airspy/CMakeLists.txt b/lib/airspy/CMakeLists.txt index 187d938..3e34aa6 100644 --- a/lib/airspy/CMakeLists.txt +++ b/lib/airspy/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,18 +21,17 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBAIRSPY_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - gnuradio::gnuradio-filter - ${Gnuradio-blocks_LIBRARIES} - ${LIBAIRSPY_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(airspy_srcs ${CMAKE_CURRENT_SOURCE_DIR}/airspy_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${airspy_srcs}) +list(APPEND gr_osmosdr_libs ${LIBAIRSPY_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES}) diff --git a/lib/airspy/airspy_source_c.cc b/lib/airspy/airspy_source_c.cc index 7fd3be8..50150e5 100644 --- a/lib/airspy/airspy_source_c.cc +++ b/lib/airspy/airspy_source_c.cc @@ -33,6 +33,7 @@ #include <boost/assign.hpp> #include <boost/format.hpp> +#include <boost/detail/endian.hpp> #include <boost/algorithm/string.hpp> #include <boost/thread/thread.hpp> @@ -290,7 +291,7 @@ int airspy_source_c::work( int noutput_items, if ( ! running ) return WORK_DONE; - std::unique_lock<std::mutex> lock(_fifo_lock); + boost::unique_lock<boost::mutex> lock(_fifo_lock); /* Wait until we have the requested number of samples */ int n_samples_avail = _fifo->size(); diff --git a/lib/airspy/airspy_source_c.h b/lib/airspy/airspy_source_c.h index a7d817f..f8617e6 100644 --- a/lib/airspy/airspy_source_c.h +++ b/lib/airspy/airspy_source_c.h @@ -23,9 +23,8 @@ #define INCLUDED_AIRSPY_SOURCE_C_H #include <boost/circular_buffer.hpp> - -#include <mutex> -#include <condition_variable> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include <gnuradio/sync_block.h> @@ -129,8 +128,8 @@ private: airspy_device *_dev; boost::circular_buffer<gr_complex> *_fifo; - std::mutex _fifo_lock; - std::condition_variable _samp_avail; + boost::mutex _fifo_lock; + boost::condition_variable _samp_avail; std::vector< std::pair<double, uint32_t> > _sample_rates; double _sample_rate; diff --git a/lib/airspyhf/airspyhf_source_c.cc b/lib/airspyhf/airspyhf_source_c.cc deleted file mode 100644 index 26e0134..0000000 --- a/lib/airspyhf/airspyhf_source_c.cc +++ /dev/null @@ -1,437 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013 Dimitri Stolnikov <horiz0n@gmx.net> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -/* - * config.h is generated by configure. It contains the results - * of probing for features, options etc. It should be the first - * file included in your .cc file. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdexcept> -#include <iostream> -#include <algorithm> - -#include <boost/assign.hpp> -#include <boost/format.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/thread/thread.hpp> - -#include <gnuradio/io_signature.h> - -#include "airspyhf_source_c.h" -#include "arg_helpers.h" - -using namespace boost::assign; - -#define AIRSPYHF_FORMAT_ERROR(ret, msg) \ - boost::str( boost::format(msg " (%1%)") % ret ) - -#define AIRSPYHF_THROW_ON_ERROR(ret, msg) \ - if ( ret != AIRSPYHF_SUCCESS ) \ - { \ - throw std::runtime_error( AIRSPYHF_FORMAT_ERROR(ret, msg) ); \ - } - -#define AIRSPYHF_FUNC_STR(func, arg) \ - boost::str(boost::format(func "(%1%)") % arg) + " has failed" - -airspyhf_source_c_sptr make_airspyhf_source_c (const std::string & args) -{ - return gnuradio::get_initial_sptr(new airspyhf_source_c (args)); -} - -/* - * Specify constraints on number of input and output streams. - * This info is used to construct the input and output signatures - * (2nd & 3rd args to gr::block's constructor). The input and - * output signatures are used by the runtime system to - * check that a valid number and type of inputs and outputs - * are connected to this block. In this case, we accept - * only 0 input and 1 output. - */ -static const int MIN_IN = 0; // mininum number of input streams -static const int MAX_IN = 0; // maximum number of input streams -static const int MIN_OUT = 1; // minimum number of output streams -static const int MAX_OUT = 1; // maximum number of output streams - -/* - * The private constructor - */ -airspyhf_source_c::airspyhf_source_c (const std::string &args) - : gr::sync_block ("airspyhf_source_c", - gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)), - gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))), - _dev(NULL), - _sample_rate(0), - _center_freq(0), - _freq_corr(0) -{ - int ret; - - dict_t dict = params_to_dict(args); - - _dev = NULL; - ret = airspyhf_open( &_dev ); - AIRSPYHF_THROW_ON_ERROR(ret, "Failed to open Airspy HF+ device") - - uint32_t num_rates; - airspyhf_get_samplerates(_dev, &num_rates, 0); - uint32_t *samplerates = (uint32_t *) malloc(num_rates * sizeof(uint32_t)); - airspyhf_get_samplerates(_dev, samplerates, num_rates); - for (size_t i = 0; i < num_rates; i++) - _sample_rates.push_back( std::pair<double, uint32_t>( samplerates[i], i ) ); - free(samplerates); - - /* since they may (and will) give us an unsorted array we have to sort it here - * to play nice with the monotonic requirement of meta-range later on */ - std::sort(_sample_rates.begin(), _sample_rates.end()); - - std::cerr << "Using libairspyhf" << AIRSPYHF_VERSION << ", samplerates: "; - - for (size_t i = 0; i < _sample_rates.size(); i++) - std::cerr << boost::format("%gM ") % (_sample_rates[i].first / 1e6); - - std::cerr << std::endl; - - set_center_freq( (get_freq_range().start() + get_freq_range().stop()) / 2.0 ); - set_sample_rate( get_sample_rates().start() ); - - _fifo = new boost::circular_buffer<gr_complex>(5000000); - if (!_fifo) { - throw std::runtime_error( std::string(__FUNCTION__) + " " + - "Failed to allocate a sample FIFO!" ); - } -} - -/* - * Our virtual destructor. - */ -airspyhf_source_c::~airspyhf_source_c () -{ - int ret; - - if (_dev) { - if ( airspyhf_is_streaming( _dev ) ) - { - ret = airspyhf_stop( _dev ); - if ( ret != AIRSPYHF_SUCCESS ) - { - std::cerr << AIRSPYHF_FORMAT_ERROR(ret, "Failed to stop RX streaming") << std::endl; - } - } - - ret = airspyhf_close( _dev ); - if ( ret != AIRSPYHF_SUCCESS ) - { - std::cerr << AIRSPYHF_FORMAT_ERROR(ret, "Failed to close AirSpy") << std::endl; - } - _dev = NULL; - } - - if (_fifo) - { - delete _fifo; - _fifo = NULL; - } -} - -int airspyhf_source_c::_airspyhf_rx_callback(airspyhf_transfer_t *transfer) -{ - airspyhf_source_c *obj = (airspyhf_source_c *)transfer->ctx; - - return obj->airspyhf_rx_callback((float *)transfer->samples, transfer->sample_count); -} - -int airspyhf_source_c::airspyhf_rx_callback(void *samples, int sample_count) -{ - size_t i, n_avail, to_copy, num_samples = sample_count; - float *sample = (float *)samples; - - _fifo_lock.lock(); - - n_avail = _fifo->capacity() - _fifo->size(); - to_copy = (n_avail < num_samples ? n_avail : num_samples); - - for (i = 0; i < to_copy; i++ ) - { - /* Push sample to the fifo */ - _fifo->push_back( gr_complex( *sample, *(sample+1) ) ); - - /* offset to the next I+Q sample */ - sample += 2; - } - - _fifo_lock.unlock(); - - /* We have made some new samples available to the consumer in work() */ - if (to_copy) { - //std::cerr << "+" << std::flush; - _samp_avail.notify_one(); - } - - /* Indicate overrun, if neccesary */ - if (to_copy < num_samples) - std::cerr << "O" << std::flush; - - return 0; // TODO: return -1 on error/stop -} - -bool airspyhf_source_c::start() -{ - if ( ! _dev ) - return false; - - int ret = airspyhf_start( _dev, _airspyhf_rx_callback, (void *)this ); - if ( ret != AIRSPYHF_SUCCESS ) { - std::cerr << "Failed to start RX streaming (" << ret << ")" << std::endl; - return false; - } - - return true; -} - -bool airspyhf_source_c::stop() -{ - if ( ! _dev ) - return false; - - int ret = airspyhf_stop( _dev ); - if ( ret != AIRSPYHF_SUCCESS ) { - std::cerr << "Failed to stop RX streaming (" << ret << ")" << std::endl; - return false; - } - - return true; -} - -int airspyhf_source_c::work( int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items ) -{ - gr_complex *out = (gr_complex *)output_items[0]; - - bool running = false; - - if ( _dev ) - running = airspyhf_is_streaming( _dev ); - - if ( ! running ) - return WORK_DONE; - - std::unique_lock<std::mutex> lock(_fifo_lock); - - /* Wait until we have the requested number of samples */ - int n_samples_avail = _fifo->size(); - - while (n_samples_avail < noutput_items) { - _samp_avail.wait(lock); - n_samples_avail = _fifo->size(); - } - - for(int i = 0; i < noutput_items; ++i) { - out[i] = _fifo->at(0); - _fifo->pop_front(); - } - - return noutput_items; -} - -std::vector<std::string> airspyhf_source_c::get_devices() -{ - std::vector<std::string> devices; - std::string label; - - int ret; - airspyhf_device *dev = NULL; - ret = airspyhf_open(&dev); - if ( AIRSPYHF_SUCCESS == ret ) - { - std::string args = "airspyhf=0,label='AirspyHF'"; - devices.push_back( args ); - ret = airspyhf_close(dev); - } - - return devices; -} - -size_t airspyhf_source_c::get_num_channels() -{ - return 1; -} - -osmosdr::meta_range_t airspyhf_source_c::get_sample_rates() -{ - osmosdr::meta_range_t range; - - for (size_t i = 0; i < _sample_rates.size(); i++) - range += osmosdr::range_t( _sample_rates[i].first ); - - return range; -} - -double airspyhf_source_c::set_sample_rate( double rate ) -{ - int ret = AIRSPYHF_SUCCESS; - - if (_dev) { - bool found_supported_rate = false; - uint32_t samp_rate_index = 0; - - for( unsigned int i = 0; i < _sample_rates.size(); i++ ) - { - if( _sample_rates[i].first == rate ) - { - samp_rate_index = _sample_rates[i].second; - - found_supported_rate = true; - } - } - - if ( ! found_supported_rate ) - { - throw std::runtime_error( - boost::str( boost::format("Unsupported samplerate: %gM") % (rate/1e6) ) ); - } - - ret = airspyhf_set_samplerate( _dev, samp_rate_index ); - if ( AIRSPYHF_SUCCESS == ret ) { - _sample_rate = rate; - } else { - AIRSPYHF_THROW_ON_ERROR( ret, AIRSPYHF_FUNC_STR( "airspyhf_set_samplerate", rate ) ) - } - } - - return get_sample_rate(); -} - -double airspyhf_source_c::get_sample_rate() -{ - return _sample_rate; -} - -osmosdr::freq_range_t airspyhf_source_c::get_freq_range( size_t chan ) -{ - osmosdr::freq_range_t range; - - range += osmosdr::range_t( 0.0, 260.0e6 ); - - return range; -} - -double airspyhf_source_c::set_center_freq( double freq, size_t chan ) -{ - int ret; - - if (_dev) { - ret = airspyhf_set_freq( _dev, freq ); - if ( AIRSPYHF_SUCCESS == ret ) { - _center_freq = freq; - } else { - AIRSPYHF_THROW_ON_ERROR( ret, AIRSPYHF_FUNC_STR( "airspyhf_set_freq", freq ) ) - } - } - - return get_center_freq( chan ); -} - -double airspyhf_source_c::get_center_freq( size_t chan ) -{ - return _center_freq; -} - -double airspyhf_source_c::set_freq_corr( double ppm, size_t chan ) -{ - int ret; - int32_t ppb = (int32_t) (ppm * 1.0e3); - - if (_dev) { - ret = airspyhf_set_calibration( _dev, ppb ); - if ( AIRSPYHF_SUCCESS == ret ) { - _freq_corr = ppm; - } else { - AIRSPYHF_THROW_ON_ERROR( ret, AIRSPYHF_FUNC_STR( "airspyhf_set_calibration", ppm ) ) - } - } - - return ppm; -} - -double airspyhf_source_c::get_freq_corr( size_t chan ) -{ - return _freq_corr; -} - -std::vector<std::string> airspyhf_source_c::get_gain_names( size_t chan ) -{ - return {}; -} - -osmosdr::gain_range_t airspyhf_source_c::get_gain_range( size_t chan ) -{ - return osmosdr::gain_range_t(); -} - -osmosdr::gain_range_t airspyhf_source_c::get_gain_range( const std::string & name, size_t chan ) -{ - return osmosdr::gain_range_t(); -} - - -double airspyhf_source_c::set_gain( double gain, size_t chan ) -{ - return gain; -} - -double airspyhf_source_c::set_gain( double gain, const std::string & name, size_t chan) -{ - return gain; -} - -double airspyhf_source_c::get_gain( size_t chan ) -{ - return 0.0; -} - -double airspyhf_source_c::get_gain( const std::string & name, size_t chan ) -{ - return 0.0; -} - -std::vector< std::string > airspyhf_source_c::get_antennas( size_t chan ) -{ - std::vector< std::string > antennas; - - antennas += get_antenna( chan ); - - return antennas; -} - -std::string airspyhf_source_c::set_antenna( const std::string & antenna, size_t chan ) -{ - return get_antenna( chan ); -} - -std::string airspyhf_source_c::get_antenna( size_t chan ) -{ - return "RX"; -} diff --git a/lib/arg_helpers.h b/lib/arg_helpers.h index 3b02b8f..2278fa9 100644 --- a/lib/arg_helpers.h +++ b/lib/arg_helpers.h @@ -29,6 +29,7 @@ #include <boost/lexical_cast.hpp> #include <boost/tokenizer.hpp> +#include <boost/foreach.hpp> #include <ciso646> typedef std::map< std::string, std::string > dict_t; @@ -37,7 +38,7 @@ typedef std::pair< std::string, std::string > pair_t; inline std::string dict_to_args_string( const dict_t &d ) { std::string out; - for (const pair_t pair : d) + BOOST_FOREACH(const pair_t pair, d) { if (not out.empty()) out += ","; out += pair.first + "='" + pair.second + "'"; @@ -53,7 +54,7 @@ inline std::vector< std::string > args_to_vector( const std::string &args ) typedef boost::tokenizer< boost::escaped_list_separator<char> > tokenizer_t; tokenizer_t tokens(args, separator); - for (std::string token : tokens) + BOOST_FOREACH(std::string token, tokens) result.push_back(token); return result; @@ -67,7 +68,7 @@ inline std::vector< std::string > params_to_vector( const std::string ¶ms ) typedef boost::tokenizer< boost::escaped_list_separator<char> > tokenizer_t; tokenizer_t tokens(params, separator); - for (std::string token : tokens) + BOOST_FOREACH(std::string token, tokens) result.push_back(token); return result; @@ -97,7 +98,7 @@ inline dict_t params_to_dict( const std::string ¶ms ) dict_t result; std::vector< std::string > param_list = params_to_vector( params ); - for (std::string param : param_list) + BOOST_FOREACH(std::string param, param_list) { pair_t pair = param_to_pair( param ); std::string value = pair.second; @@ -123,7 +124,7 @@ inline gr::io_signature::sptr args_to_io_signature( const std::string &args ) size_t dev_nchan = 0; std::vector< std::string > arg_list = args_to_vector( args ); - for (std::string arg : arg_list) + BOOST_FOREACH( std::string arg, arg_list ) { if ( arg.find( "numchan=" ) == 0 ) // try to parse global nchan value { @@ -140,7 +141,7 @@ inline gr::io_signature::sptr args_to_io_signature( const std::string &args ) // try to parse device specific nchan values, assume 1 channel if none given - for (std::string arg : arg_list) + BOOST_FOREACH( std::string arg, arg_list ) { dict_t dict = params_to_dict(arg); if (dict.count("nchan")) @@ -153,6 +154,8 @@ inline gr::io_signature::sptr args_to_io_signature( const std::string &args ) } } + if (arg_list.size() <= 2 && max_nchan > dev_nchan) + dev_nchan = max_nchan; // if at least one nchan was given, perform a sanity check if ( max_nchan && dev_nchan && max_nchan != dev_nchan ) throw std::runtime_error("Wrong device arguments specified. Missing nchan?"); diff --git a/lib/bladerf/CMakeLists.txt b/lib/bladerf/CMakeLists.txt index ea9cf49..c253a22 100644 --- a/lib/bladerf/CMakeLists.txt +++ b/lib/bladerf/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2013 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,20 +21,20 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBBLADERF_INCLUDE_DIRS} - ${Volk_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${LIBBLADERF_LIBRARIES} - ${Volk_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(bladerf_srcs ${CMAKE_CURRENT_SOURCE_DIR}/bladerf_source_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/bladerf_sink_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/bladerf_common.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${bladerf_srcs}) +list(APPEND gr_osmosdr_libs ${LIBBLADERF_LIBRARIES} ${VOLK_LIBRARIES}) diff --git a/lib/bladerf/bladerf_common.cc b/lib/bladerf/bladerf_common.cc index 67bf736..93b039d 100644 --- a/lib/bladerf/bladerf_common.cc +++ b/lib/bladerf/bladerf_common.cc @@ -35,8 +35,10 @@ #include <string> #include <boost/assign.hpp> +#include <boost/foreach.hpp> #include <boost/format.hpp> #include <boost/lexical_cast.hpp> +#include <boost/weak_ptr.hpp> #include "bladerf_common.h" @@ -48,8 +50,8 @@ static size_t const STREAM_TIMEOUT_MS = 3000; using namespace boost::assign; -std::mutex bladerf_common::_devs_mutex; -std::list<std::weak_ptr<struct bladerf>> bladerf_common::_devs; +boost::mutex bladerf_common::_devs_mutex; +std::list<boost::weak_ptr<struct bladerf> > bladerf_common::_devs; /* name for system-wide gain (which is not its own libbladeRF gain stage) */ static const char *SYSTEM_GAIN_NAME = "system"; @@ -133,7 +135,7 @@ size_t num_streams(bladerf_channel_layout layout) * Public methods ******************************************************************************/ bladerf_common::bladerf_common() : - _dev(NULL), + _dev(boost::shared_ptr<struct bladerf>()), _pfx("[bladeRF common] "), _failures(0), _num_buffers(NUM_BUFFERS), @@ -497,7 +499,7 @@ int bladerf_common::channel2rfport(bladerf_channel ch) bladerf_channel bladerf_common::chan2channel(bladerf_direction direction, size_t chan) { - for (bladerf_channel_map::value_type &i : _chanmap) { + BOOST_FOREACH(bladerf_channel_map::value_type &i, _chanmap) { bladerf_channel ch = i.first; if ( (i.second == (int)chan) && ( @@ -641,7 +643,7 @@ osmosdr::freq_range_t bladerf_common::filter_bandwidths(bladerf_channel ch) 0.75, 0.875, 1.25, 1.375, 1.5, 1.92, 2.5, 2.75, 3, 3.5, 4.375, 5, 6, 7, 10, 14; - for (double half_bw : half_bandwidths) + BOOST_FOREACH( double half_bw, half_bandwidths ) bandwidths += osmosdr::range_t( half_bw * 2e6 ); #else @@ -1077,7 +1079,7 @@ bladerf_sptr bladerf_common::open(std::string const &device_name) struct bladerf *raw_dev = NULL; struct bladerf_devinfo devinfo; - std::lock_guard<std::mutex> lock(_devs_mutex); + boost::unique_lock<boost::mutex> lock(_devs_mutex); /* Initialize the information used to identify the desired device * to all wildcard (i.e., "any device") values */ @@ -1107,15 +1109,15 @@ bladerf_sptr bladerf_common::open(std::string const &device_name) /* Add the device handle to our cache */ bladerf_sptr dev = bladerf_sptr(raw_dev, bladerf_common::close); - _devs.push_back(static_cast<std::weak_ptr<struct bladerf>>(dev)); + _devs.push_back(static_cast<boost::weak_ptr<struct bladerf> >(dev)); return dev; } void bladerf_common::close(void *dev) { - std::lock_guard<std::mutex> lock(_devs_mutex); - std::list<std::weak_ptr<struct bladerf>>::iterator it(_devs.begin()); + boost::unique_lock<boost::mutex> lock(_devs_mutex); + std::list<boost::weak_ptr<struct bladerf> >::iterator it(_devs.begin()); /* Prune expired entries from device cache */ while (it != _devs.end()) { @@ -1135,7 +1137,7 @@ bladerf_sptr bladerf_common::get_cached_device(struct bladerf_devinfo devinfo) int status; struct bladerf_devinfo other_devinfo; - for (std::weak_ptr<struct bladerf> dev : _devs) { + BOOST_FOREACH(boost::weak_ptr<struct bladerf> dev, _devs) { status = bladerf_get_devinfo(bladerf_sptr(dev).get(), &other_devinfo); if (status < 0) { BLADERF_THROW_STATUS(status, "Failed to get devinfo for cached device"); @@ -1198,7 +1200,7 @@ void bladerf_common::print_device_info() bool bladerf_common::is_antenna_valid(bladerf_direction dir, const std::string &antenna) { - for (std::string ant : get_antennas(dir)) { + BOOST_FOREACH(std::string ant, get_antennas(dir)) { if (antenna == ant) { return true; } diff --git a/lib/bladerf/bladerf_common.h b/lib/bladerf/bladerf_common.h index 741b1e7..51dedc9 100644 --- a/lib/bladerf/bladerf_common.h +++ b/lib/bladerf/bladerf_common.h @@ -23,11 +23,12 @@ #include <list> #include <map> -#include <memory> -#include <mutex> #include <string> #include <vector> +#include <boost/thread/mutex.hpp> +#include <boost/weak_ptr.hpp> + #include <libbladeRF.h> #include "osmosdr/ranges.h" @@ -42,7 +43,7 @@ typedef ptrdiff_t ssize_t; #define BLADERF_DEBUG_ENABLE -typedef std::shared_ptr<struct bladerf> bladerf_sptr; +typedef boost::shared_ptr<struct bladerf> bladerf_sptr; /* Identification of the bladeRF hardware in use */ typedef enum { @@ -286,8 +287,8 @@ private: /***************************************************************************** * Private members ****************************************************************************/ - static std::mutex _devs_mutex; /**< mutex for access to _devs */ - static std::list<std::weak_ptr<struct bladerf>> _devs; /**< dev cache */ + static boost::mutex _devs_mutex; /**< mutex for access to _devs */ + static std::list<boost::weak_ptr<struct bladerf> > _devs; /**< dev cache */ }; #endif diff --git a/lib/bladerf/bladerf_compat.h b/lib/bladerf/bladerf_compat.h index 2ad24be..45e6a16 100644 --- a/lib/bladerf/bladerf_compat.h +++ b/lib/bladerf/bladerf_compat.h @@ -66,7 +66,7 @@ } /* Changed enums/defines */ - #define BLADERF_GAIN_DEFAULT BLADERF_GAIN_AUTOMATIC + #define BLADERF_GAIN_DEFAULT BLADERF_GAIN_MANUAL #define BLADERF_GAIN_MGC BLADERF_GAIN_MANUAL #define BLADERF_RX_MUX_BASEBAND BLADERF_RX_MUX_BASEBAND_LMS diff --git a/lib/bladerf/bladerf_sink_c.cc b/lib/bladerf/bladerf_sink_c.cc index 6ee3acd..d3d607b 100644 --- a/lib/bladerf/bladerf_sink_c.cc +++ b/lib/bladerf/bladerf_sink_c.cc @@ -96,7 +96,7 @@ bladerf_sink_c::bladerf_sink_c(const std::string &args) : } /* Initialize channel <-> antenna map */ - for (std::string ant : get_antennas()) { + BOOST_FOREACH(std::string ant, get_antennas()) { _chanmap[str2channel(ant)] = -1; } @@ -174,11 +174,9 @@ bool bladerf_sink_c::start() for (size_t ch = 0; ch < get_max_channels(); ++ch) { bladerf_channel brfch = BLADERF_CHANNEL_TX(ch); - if (get_channel_enable(brfch)) { - status = bladerf_enable_module(_dev.get(), brfch, true); - if (status != 0) { - BLADERF_THROW_STATUS(status, "bladerf_enable_module failed"); - } + status = bladerf_enable_module(_dev.get(), brfch, get_channel_enable(brfch)); + if (status != 0) { + BLADERF_THROW_STATUS(status, "bladerf_enable_module failed"); } } @@ -210,11 +208,9 @@ bool bladerf_sink_c::stop() for (size_t ch = 0; ch < get_max_channels(); ++ch) { bladerf_channel brfch = BLADERF_CHANNEL_TX(ch); - if (get_channel_enable(brfch)) { - status = bladerf_enable_module(_dev.get(), brfch, false); - if (status != 0) { - BLADERF_THROW_STATUS(status, "bladerf_enable_module failed"); - } + status = bladerf_enable_module(_dev.get(), brfch, get_channel_enable(brfch)); + if (status != 0) { + BLADERF_THROW_STATUS(status, "bladerf_enable_module failed"); } } @@ -241,6 +237,11 @@ int bladerf_sink_c::work(int noutput_items, return 0; } + noutput_items &= ~(3ULL); + if (!noutput_items) { + return 0; + } + // copy the samples from input_items gr_complex const **in = reinterpret_cast<gr_complex const **>(&input_items[0]); @@ -329,7 +330,7 @@ int bladerf_sink_c::transmit_with_tags(int16_t const *samples, } } - for (gr::tag_t tag : tags) { + BOOST_FOREACH(gr::tag_t tag, tags) { // Upon seeing an SOB tag, update our offset. We'll TX the start of the // burst when we see an EOB or at the end of this function - whichever // occurs first. diff --git a/lib/bladerf/bladerf_source_c.cc b/lib/bladerf/bladerf_source_c.cc index 83db677..e37bd67 100644 --- a/lib/bladerf/bladerf_source_c.cc +++ b/lib/bladerf/bladerf_source_c.cc @@ -144,7 +144,7 @@ bladerf_source_c::bladerf_source_c(const std::string &args) : } /* Initialize channel <-> antenna map */ - for (std::string ant : get_antennas()) { + BOOST_FOREACH(std::string ant, get_antennas()) { _chanmap[str2channel(ant)] = -1; } @@ -180,7 +180,7 @@ bladerf_source_c::bladerf_source_c(const std::string &args) : bool bladerf_source_c::is_antenna_valid(const std::string &antenna) { - for (std::string ant : get_antennas()) { + BOOST_FOREACH(std::string ant, get_antennas()) { if (antenna == ant) { return true; } @@ -230,11 +230,9 @@ bool bladerf_source_c::start() for (size_t ch = 0; ch < get_max_channels(); ++ch) { bladerf_channel brfch = BLADERF_CHANNEL_RX(ch); - if (get_channel_enable(brfch)) { - status = bladerf_enable_module(_dev.get(), brfch, true); - if (status != 0) { - BLADERF_THROW_STATUS(status, "bladerf_enable_module failed"); - } + status = bladerf_enable_module(_dev.get(), brfch, get_channel_enable(brfch)); + if (status != 0) { + BLADERF_THROW_STATUS(status, "bladerf_enable_module failed"); } } @@ -344,7 +342,7 @@ int bladerf_source_c::work(int noutput_items, memcpy(out[0], _32fcbuf, sizeof(gr_complex) * noutput_items); } - return noutput_items; + return noutput_items/(get_num_channels()); } osmosdr::meta_range_t bladerf_source_c::get_sample_rates() diff --git a/lib/config.h.in b/lib/config.h.in index d96cd80..42e72f1 100644 --- a/lib/config.h.in +++ b/lib/config.h.in @@ -4,21 +4,21 @@ #define GR_OSMOSDR_VERSION "@VERSION@" #define GR_OSMOSDR_LIBVER "@LIBVER@" +#cmakedefine ENABLE_OSMOSDR #cmakedefine ENABLE_FCD #cmakedefine ENABLE_FILE #cmakedefine ENABLE_RTL #cmakedefine ENABLE_RTL_TCP #cmakedefine ENABLE_UHD +#cmakedefine ENABLE_MIRI #cmakedefine ENABLE_SDRPLAY #cmakedefine ENABLE_HACKRF #cmakedefine ENABLE_BLADERF #cmakedefine ENABLE_RFSPACE #cmakedefine ENABLE_AIRSPY -#cmakedefine ENABLE_AIRSPYHF #cmakedefine ENABLE_SOAPY #cmakedefine ENABLE_REDPITAYA #cmakedefine ENABLE_FREESRP -#cmakedefine ENABLE_XTRX //provide NAN define for MSVC older than VC12 #if defined(_MSC_VER) && (_MSC_VER < 1800) diff --git a/lib/device.cc b/lib/device.cc index d072e27..025a22b 100644 --- a/lib/device.cc +++ b/lib/device.cc @@ -20,15 +20,20 @@ #include <osmosdr/device.h> #include <stdexcept> +#include <boost/foreach.hpp> #include <boost/format.hpp> +#include <boost/thread/mutex.hpp> #include <algorithm> -#include <mutex> #include <sstream> #ifdef HAVE_CONFIG_H #include "config.h" #endif +#ifdef ENABLE_OSMOSDR +#include <osmosdr_src_c.h> +#endif + #ifdef ENABLE_FCD #include <fcd_source_c.h> #endif @@ -49,6 +54,10 @@ #include <uhd_source_c.h> #endif +#ifdef ENABLE_MIRI +#include <miri_source_c.h> +#endif + #ifdef ENABLE_SDRPLAY #include <sdrplay_source_c.h> #endif @@ -69,10 +78,6 @@ #include <airspy_source_c.h> #endif -#ifdef ENABLE_AIRSPYHF -#include <airspyhf_source_c.h> -#endif - #ifdef ENABLE_SOAPY #include <soapy_source_c.h> #endif @@ -93,13 +98,13 @@ static const std::string args_delim = " "; static const std::string pairs_delim = ","; static const std::string pair_delim = "="; -static std::mutex _device_mutex; +static boost::mutex _device_mutex; device_t::device_t(const std::string &args) { dict_t dict = params_to_dict(args); - for (dict_t::value_type &entry : dict) + BOOST_FOREACH( dict_t::value_type &entry, dict ) (*this)[entry.first] = entry.second; } @@ -109,7 +114,7 @@ std::string device_t::to_pp_string(void) const std::stringstream ss; ss << "Device Address:" << std::endl; - for (const device_t::value_type &entry : *this) { + BOOST_FOREACH(const device_t::value_type &entry, *this) { ss << boost::format(" %s: %s") % entry.first % entry.second << std::endl; } return ss.str(); @@ -119,7 +124,7 @@ std::string device_t::to_string(void) const { std::stringstream ss; size_t count = 0; - for (const device_t::value_type &entry : *this) { + BOOST_FOREACH(const device_t::value_type &entry, *this) { std::string value = entry.second; if (value.find(" ") != std::string::npos) value = "'" + value + "'"; @@ -132,7 +137,7 @@ std::string device_t::to_string(void) const devices_t device::find(const device_t &hint) { - std::lock_guard<std::mutex> lock(_device_mutex); + boost::mutex::scoped_lock lock(_device_mutex); bool fake = true; @@ -141,48 +146,52 @@ devices_t device::find(const device_t &hint) devices_t devices; +#ifdef ENABLE_OSMOSDR + BOOST_FOREACH( std::string dev, osmosdr_src_c::get_devices() ) + devices.push_back( device_t(dev) ); +#endif #ifdef ENABLE_FCD - for (std::string dev : fcd_source_c::get_devices()) + BOOST_FOREACH( std::string dev, fcd_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_RTL - for (std::string dev : rtl_source_c::get_devices()) + BOOST_FOREACH( std::string dev, rtl_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_UHD - for (std::string dev : uhd_source_c::get_devices()) + BOOST_FOREACH( std::string dev, uhd_source_c::get_devices() ) + devices.push_back( device_t(dev) ); +#endif +#ifdef ENABLE_MIRI + BOOST_FOREACH( std::string dev, miri_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_SDRPLAY - for (std::string dev : sdrplay_source_c::get_devices()) + BOOST_FOREACH( std::string dev, sdrplay_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_BLADERF - for (std::string dev : bladerf_source_c::get_devices()) + BOOST_FOREACH( std::string dev, bladerf_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_HACKRF - for (std::string dev : hackrf_source_c::get_devices()) + BOOST_FOREACH( std::string dev, hackrf_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_RFSPACE - for (std::string dev : rfspace_source_c::get_devices( fake )) + BOOST_FOREACH( std::string dev, rfspace_source_c::get_devices( fake ) ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_AIRSPY - for (std::string dev : airspy_source_c::get_devices()) - devices.push_back( device_t(dev) ); -#endif -#ifdef ENABLE_AIRSPYHF - for (std::string dev : airspyhf_source_c::get_devices()) + BOOST_FOREACH( std::string dev, airspy_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_FREESRP - for (std::string dev : freesrp_source_c::get_devices()) + BOOST_FOREACH( std::string dev, freesrp_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_SOAPY - for (std::string dev : soapy_source_c::get_devices()) + BOOST_FOREACH( std::string dev, soapy_source_c::get_devices() ) devices.push_back( device_t(dev) ); #endif @@ -191,15 +200,15 @@ devices_t device::find(const device_t &hint) * in a graphical interface etc... */ #ifdef ENABLE_RTL_TCP - for (std::string dev : rtl_tcp_source_c::get_devices( fake )) + BOOST_FOREACH( std::string dev, rtl_tcp_source_c::get_devices( fake ) ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_REDPITAYA - for (std::string dev : redpitaya_source_c::get_devices( fake )) + BOOST_FOREACH( std::string dev, redpitaya_source_c::get_devices( fake ) ) devices.push_back( device_t(dev) ); #endif #ifdef ENABLE_FILE - for (std::string dev : file_source_c::get_devices( fake )) + BOOST_FOREACH( std::string dev, file_source_c::get_devices( fake ) ) devices.push_back( device_t(dev) ); #endif diff --git a/lib/fcd/CMakeLists.txt b/lib/fcd/CMakeLists.txt index 768c5b2..e71b153 100644 --- a/lib/fcd/CMakeLists.txt +++ b/lib/fcd/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,16 +21,29 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${GNURADIO_FCDPP_INCLUDE_DIRS} -) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -APPEND_LIB_LIST( - ${GNURADIO_FCDPP_LIBRARIES} -) +if(ENABLE_FCD) +include_directories(${GNURADIO_FCD_INCLUDE_DIRS}) +endif(ENABLE_FCD) -list(APPEND gr_osmosdr_srcs +if(ENABLE_FCDPP) +include_directories(${GNURADIO_FCDPP_INCLUDE_DIRS}) +endif(ENABLE_FCDPP) + +set(fcd_srcs ${CMAKE_CURRENT_SOURCE_DIR}/fcd_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${fcd_srcs}) + +if(ENABLE_FCD) +list(APPEND gr_osmosdr_libs ${GNURADIO_FCD_LIBRARIES}) +endif(ENABLE_FCD) + +if(ENABLE_FCDPP) +list(APPEND gr_osmosdr_libs ${GNURADIO_FCDPP_LIBRARIES}) +endif(ENABLE_FCDPP) diff --git a/lib/fcd/fcd_source_c.cc b/lib/fcd/fcd_source_c.cc index 854e4c0..885d514 100644 --- a/lib/fcd/fcd_source_c.cc +++ b/lib/fcd/fcd_source_c.cc @@ -23,6 +23,7 @@ #include <sstream> #include <boost/assign.hpp> +#include <boost/foreach.hpp> #include <gnuradio/io_signature.h> @@ -141,15 +142,18 @@ fcd_source_c::fcd_source_c(const std::string &args) : std::cerr << "Using " << name() << " (" << dev_name << ")" << std::endl; +#ifdef HAVE_FCD if ( FUNCUBE_V1 == _type ) { - _src_v1 = gr::fcdproplus::fcd::make( dev_name ); + _src_v1 = gr::fcd::source_c::make( dev_name ); connect( _src_v1, 0, self(), 0 ); set_gain( 20, "LNA" ); set_gain( 12, "MIX" ); } +#endif +#ifdef HAVE_FCDPP if ( FUNCUBE_V2 == _type ) { _src_v2 = gr::fcdproplus::fcdproplus::make( dev_name ); @@ -159,6 +163,7 @@ fcd_source_c::fcd_source_c(const std::string &args) : set_gain( 1, "MIX" ); set_gain( 15, "BB" ); } +#endif } fcd_source_c::~fcd_source_c() @@ -170,7 +175,7 @@ std::vector< std::string > fcd_source_c::get_devices() int id = 0; std::vector< std::string > devices; - for (device_t dev : _get_devices()) + BOOST_FOREACH( device_t dev, _get_devices() ) { std::string args = "fcd=" + boost::lexical_cast< std::string >( id++ ); @@ -236,11 +241,15 @@ osmosdr::freq_range_t fcd_source_c::get_freq_range( size_t chan ) double fcd_source_c::set_center_freq( double freq, size_t chan ) { +#ifdef HAVE_FCD if ( FUNCUBE_V1 == _type ) _src_v1->set_freq( float(freq) ); +#endif +#ifdef HAVE_FCDPP if ( FUNCUBE_V2 == _type ) _src_v2->set_freq( float(freq) ); +#endif _freq = freq; @@ -254,11 +263,15 @@ double fcd_source_c::get_center_freq( size_t chan ) double fcd_source_c::set_freq_corr( double ppm, size_t chan ) { +#ifdef HAVE_FCD if ( FUNCUBE_V1 == _type ) _src_v1->set_freq_corr( ppm ); +#endif +#ifdef HAVE_FCDPP if ( FUNCUBE_V2 == _type ) _src_v2->set_freq_corr( ppm ); +#endif _correct = ppm; @@ -330,6 +343,7 @@ double fcd_source_c::set_gain( double gain, size_t chan ) double fcd_source_c::set_gain( double gain, const std::string & name, size_t chan ) { +#ifdef HAVE_FCD if ( FUNCUBE_V1 == _type ) { if ( "LNA" == name ) @@ -343,7 +357,9 @@ double fcd_source_c::set_gain( double gain, const std::string & name, size_t cha _src_v1->set_mixer_gain(_mix_gain); } } +#endif +#ifdef HAVE_FCDPP if ( FUNCUBE_V2 == _type ) { if ( "LNA" == name ) @@ -362,6 +378,7 @@ double fcd_source_c::set_gain( double gain, const std::string & name, size_t cha _src_v2->set_if_gain(_bb_gain); } } +#endif return get_gain( name, chan ); } diff --git a/lib/fcd/fcd_source_c.h b/lib/fcd/fcd_source_c.h index 2b02eb1..70239f8 100644 --- a/lib/fcd/fcd_source_c.h +++ b/lib/fcd/fcd_source_c.h @@ -22,8 +22,13 @@ #include <gnuradio/hier_block2.h> -#include <fcdproplus/fcd.h> +#ifdef HAVE_FCD +#include <gnuradio/fcd/source_c.h> +#endif + +#ifdef HAVE_FCDPP #include <fcdproplus/fcdproplus.h> +#endif #include "source_iface.h" @@ -81,8 +86,12 @@ public: private: dongle_type _type; - gr::fcdproplus::fcd::sptr _src_v1; +#ifdef HAVE_FCD + gr::fcd::source_c::sptr _src_v1; +#endif +#ifdef HAVE_FCDPP gr::fcdproplus::fcdproplus::sptr _src_v2; +#endif double _lna_gain, _mix_gain, _bb_gain, _freq; int _correct; }; diff --git a/lib/file/CMakeLists.txt b/lib/file/CMakeLists.txt index c96632d..6c55e85 100644 --- a/lib/file/CMakeLists.txt +++ b/lib/file/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,17 +21,18 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -APPEND_LIB_LIST( - gnuradio::gnuradio-blocks -) -message(STATUS ${gnuradio-blocks_LIBRARIES}) - -list(APPEND gr_osmosdr_srcs +set(file_srcs ${CMAKE_CURRENT_SOURCE_DIR}/file_source_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/file_sink_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${file_srcs}) +#list(APPEND gr_osmosdr_libs ${GNURADIO_BLOCKS_LIBRARIES}) + diff --git a/lib/freesrp/CMakeLists.txt b/lib/freesrp/CMakeLists.txt index aca0d8c..46df7e4 100644 --- a/lib/freesrp/CMakeLists.txt +++ b/lib/freesrp/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,18 +21,19 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBFREESRP_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${LIBFREESRP_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(freesrp_srcs ${CMAKE_CURRENT_SOURCE_DIR}/freesrp_common.cc ${CMAKE_CURRENT_SOURCE_DIR}/freesrp_source_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/freesrp_sink_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${freesrp_srcs}) +list(APPEND gr_osmosdr_libs ${LIBFREESRP_LIBRARIES}) diff --git a/lib/freesrp/freesrp_common.cc b/lib/freesrp/freesrp_common.cc index 57bbdbb..d60fbb8 100644 --- a/lib/freesrp/freesrp_common.cc +++ b/lib/freesrp/freesrp_common.cc @@ -2,6 +2,7 @@ #include <cstdlib> +#include <boost/make_shared.hpp> #include <boost/assign.hpp> #include <arg_helpers.h> @@ -10,7 +11,7 @@ using namespace FreeSRP; using namespace std; using namespace boost::assign; -std::shared_ptr<::FreeSRP::FreeSRP> freesrp_common::_srp; +boost::shared_ptr<::FreeSRP::FreeSRP> freesrp_common::_srp; freesrp_common::freesrp_common(const string &args) { diff --git a/lib/freesrp/freesrp_common.h b/lib/freesrp/freesrp_common.h index 8d13c47..9a5687c 100644 --- a/lib/freesrp/freesrp_common.h +++ b/lib/freesrp/freesrp_common.h @@ -1,7 +1,6 @@ #ifndef INCLUDED_FREESRP_COMMON_H #define INCLUDED_FREESRP_COMMON_H -#include <memory> #include <vector> #include <string> @@ -23,7 +22,7 @@ public: double set_freq_corr( double ppm, size_t chan = 0 ); double get_freq_corr( size_t chan = 0 ); protected: - static std::shared_ptr<::FreeSRP::FreeSRP> _srp; + static boost::shared_ptr<::FreeSRP::FreeSRP> _srp; bool _ignore_overflow = false; }; diff --git a/lib/gnuradio-osmosdr.rc.in b/lib/gnuradio-osmosdr.rc.in new file mode 100644 index 0000000..62fd5ea --- /dev/null +++ b/lib/gnuradio-osmosdr.rc.in @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <afxres.h> + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @MAJOR_VERSION@,@API_COMPAT@,@RC_MINOR_VERSION@,@RC_MAINT_VERSION@ + PRODUCTVERSION @MAJOR_VERSION@,@API_COMPAT@,@RC_MINOR_VERSION@,@RC_MAINT_VERSION@ + FILEFLAGSMASK 0x3fL +#ifndef NDEBUG + FILEFLAGS 0x0L +#else + FILEFLAGS 0x1L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_DRV_INSTALLABLE + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "gnuradio-osmosdr" + VALUE "FileVersion", "@VERSION@" + VALUE "InternalName", "gnuradio-osmosdr.dll" + VALUE "LegalCopyright", "Licensed under GPLv3 or any later version" + VALUE "OriginalFilename", "gnuradio-osmosdr.dll" + VALUE "ProductName", "gnuradio-osmosdr" + VALUE "ProductVersion", "@VERSION@" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END + END diff --git a/lib/hackrf/CMakeLists.txt b/lib/hackrf/CMakeLists.txt index a0ec70a..c7af0c9 100644 --- a/lib/hackrf/CMakeLists.txt +++ b/lib/hackrf/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,18 +21,27 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBHACKRF_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${LIBHACKRF_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs - ${CMAKE_CURRENT_SOURCE_DIR}/hackrf_common.cc +set(hackrf_srcs ${CMAKE_CURRENT_SOURCE_DIR}/hackrf_source_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/hackrf_sink_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +INCLUDE(CheckFunctionExists) +set(CMAKE_REQUIRED_LIBRARIES ${LIBHACKRF_LIBRARIES}) +CHECK_FUNCTION_EXISTS(hackrf_device_list LIBHACKRF_HAVE_DEVICE_LIST) + +if(LIBHACKRF_HAVE_DEVICE_LIST) + message(STATUS "HackRF multiple device support enabled") + add_definitions(-DLIBHACKRF_HAVE_DEVICE_LIST) +endif(LIBHACKRF_HAVE_DEVICE_LIST) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${hackrf_srcs}) +list(APPEND gr_osmosdr_libs ${LIBHACKRF_LIBRARIES}) diff --git a/lib/hackrf/hackrf_common.cc b/lib/hackrf/hackrf_common.cc deleted file mode 100644 index 666dc60..0000000 --- a/lib/hackrf/hackrf_common.cc +++ /dev/null @@ -1,427 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2020 Clayton Smith <argilo@gmail.com> - * - * gr-osmosdr 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, or (at your option) - * any later version. - * - * gr-osmosdr 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 gr-osmosdr; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "hackrf_common.h" - -#include "arg_helpers.h" - -int hackrf_common::_usage = 0; -std::mutex hackrf_common::_usage_mutex; - -std::map<std::string, std::weak_ptr<hackrf_device>> hackrf_common::_devs; -std::mutex hackrf_common::_devs_mutex; - -hackrf_common::hackrf_common(const std::string &args) : - _dev(NULL), - _sample_rate(0), - _center_freq(0), - _freq_corr(0), - _auto_gain(false), - _requested_bandwidth(0), - _bandwidth(0), - _bias(false), - _started(false) -{ - int ret; - hackrf_device *raw_dev; - hackrf_device_list_t *list; - int dev_index; - std::string target_serial = "0"; - std::string final_serial = ""; - - dict_t dict = params_to_dict(args); - if (dict.count("hackrf") > 0 && dict["hackrf"].length() > 0) { - target_serial = dict["hackrf"]; - } - - { - std::lock_guard<std::mutex> guard(_usage_mutex); - - if (_usage == 0) { - hackrf_init(); /* call only once before the first open */ - } - - _usage++; - } - - list = hackrf_device_list(); - - if (target_serial.length() > 1) { - for (dev_index = 0; dev_index < list->devicecount; dev_index++) { - if (list->serial_numbers[dev_index]) { - std::string serial(list->serial_numbers[dev_index]); - if (serial.compare(serial.length() - target_serial.length(), - target_serial.length(), target_serial) == 0) { - break; - } - } - } - - if (dev_index >= list->devicecount) { - hackrf_device_list_free(list); - throw std::runtime_error( - "No device found with serial number '" + target_serial + "'"); - } - } else { - try { - dev_index = std::stoi(target_serial); - } catch (std::exception &ex) { - hackrf_device_list_free(list); - throw std::runtime_error( - "Failed to use '" + target_serial + "' as HackRF device index number"); - } - - if (dev_index >= list->devicecount) { - hackrf_device_list_free(list); - throw std::runtime_error( - "Failed to use '" + target_serial + "' as HackRF device index: not enough devices"); - } - } - - if (list->serial_numbers[dev_index]) { - final_serial = list->serial_numbers[dev_index]; - } - - { - std::lock_guard<std::mutex> guard(_devs_mutex); - - if (_devs.count(final_serial) > 0 && !_devs[final_serial].expired()) { - _dev = hackrf_sptr(_devs[final_serial]); - } else { - ret = hackrf_device_list_open(list, dev_index, &raw_dev); - HACKRF_THROW_ON_ERROR(ret, "Failed to open HackRF device") - _dev = hackrf_sptr(raw_dev, hackrf_common::close); - _devs[final_serial] = static_cast<std::weak_ptr<struct hackrf_device>>(_dev); - } - } - - hackrf_device_list_free(list); - - uint8_t board_id; - ret = hackrf_board_id_read(_dev.get(), &board_id); - HACKRF_THROW_ON_ERROR(ret, "Failed to get HackRF board id") - - char version[40]; - memset(version, 0, sizeof(version)); - ret = hackrf_version_string_read(_dev.get(), version, sizeof(version)); - HACKRF_THROW_ON_ERROR(ret, "Failed to read version string") - - std::cerr << "Using " << hackrf_board_id_name(hackrf_board_id(board_id)) << " " - << "with firmware " << version - << std::endl; -} - -void hackrf_common::close(void *dev) -{ - int ret = hackrf_close(static_cast<hackrf_device *>(dev)); - if (ret != HACKRF_SUCCESS) - { - std::cerr << HACKRF_FORMAT_ERROR(ret, "Failed to close HackRF") << std::endl; - } - - { - std::lock_guard<std::mutex> guard(_usage_mutex); - - _usage--; - - if (_usage == 0) { - hackrf_exit(); /* call only once after last close */ - } - } -} - -std::vector<std::string> hackrf_common::get_devices() -{ - std::vector<std::string> devices; - std::string label; - - { - std::lock_guard<std::mutex> guard(_usage_mutex); - - if (_usage == 0) { - hackrf_init(); /* call only once before the first open */ - } - - _usage++; - } - - hackrf_device_list_t *list = hackrf_device_list(); - - for (int i = 0; i < list->devicecount; i++) { - label = "HackRF "; - label += hackrf_usb_board_id_name(list->usb_board_ids[i]); - - std::string args; - if (list->serial_numbers[i]) { - std::string serial(list->serial_numbers[i]); - if (serial.length() > 6) - serial = serial.substr(serial.length() - 6, 6); - args = "hackrf=" + serial; - if (serial.length() ) - label += " " + serial; - } else { - args = "hackrf"; /* will pick the first one, serial number is required for choosing a specific one */ - } - - args += ",label='" + label + "'"; - devices.push_back(args); - } - - hackrf_device_list_free(list); - - { - std::lock_guard<std::mutex> guard(_usage_mutex); - - _usage--; - - if (_usage == 0) { - hackrf_exit(); /* call only once after last close */ - } - } - - return devices; -} - -osmosdr::meta_range_t hackrf_common::get_sample_rates() -{ - osmosdr::meta_range_t range; - - /* we only add integer rates here because of better phase noise performance. - * the user is allowed to request arbitrary (fractional) rates within these - * boundaries. */ - - range.push_back(osmosdr::range_t( 8e6 )); - range.push_back(osmosdr::range_t( 10e6 )); - range.push_back(osmosdr::range_t( 12.5e6 )); - range.push_back(osmosdr::range_t( 16e6 )); - range.push_back(osmosdr::range_t( 20e6 )); /* confirmed to work on fast machines */ - - return range; -} - -double hackrf_common::set_sample_rate( double rate ) -{ - int ret; - - if (_dev.get() && _started) { - ret = hackrf_set_sample_rate( _dev.get(), rate ); - if ( HACKRF_SUCCESS != ret ) { - HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_sample_rate", rate ) ) - } - } - - _sample_rate = rate; - return get_sample_rate(); -} - -double hackrf_common::get_sample_rate() -{ - return _sample_rate; -} - -osmosdr::freq_range_t hackrf_common::get_freq_range( size_t chan ) -{ - osmosdr::freq_range_t range; - - range.push_back(osmosdr::range_t( _sample_rate / 2, 7250e6 - _sample_rate / 2 )); - - return range; -} - -double hackrf_common::set_center_freq( double freq, size_t chan ) -{ - int ret; - - #define APPLY_PPM_CORR(val, ppm) ((val) * (1.0 + (ppm) * 0.000001)) - - if (_dev.get() && _started) { - double corr_freq = APPLY_PPM_CORR( freq, _freq_corr ); - ret = hackrf_set_freq( _dev.get(), uint64_t(corr_freq) ); - if ( HACKRF_SUCCESS != ret ) { - HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_freq", corr_freq ) ) - } - } - - _center_freq = freq; - return get_center_freq( chan ); -} - -double hackrf_common::get_center_freq( size_t chan ) -{ - return _center_freq; -} - -double hackrf_common::set_freq_corr( double ppm, size_t chan ) -{ - _freq_corr = ppm; - - set_center_freq( _center_freq ); - - return get_freq_corr( chan ); -} - -double hackrf_common::get_freq_corr( size_t chan ) -{ - return _freq_corr; -} - -bool hackrf_common::set_gain_mode( bool automatic, size_t chan ) -{ - _auto_gain = automatic; - - return get_gain_mode(chan); -} - -bool hackrf_common::get_gain_mode( size_t chan ) -{ - return _auto_gain; -} - -double hackrf_common::set_gain( double gain, size_t chan ) -{ - int ret; - double clip_gain = (gain >= 14.0) ? 14.0 : 0.0; - - if (_dev.get() && _started) { - uint8_t value = (clip_gain == 14.0) ? 1 : 0; - - ret = hackrf_set_amp_enable( _dev.get(), value ); - if ( HACKRF_SUCCESS != ret ) { - HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_amp_enable", value ) ) - } - } - - _amp_gain = clip_gain; - return hackrf_common::get_gain(chan); -} - -double hackrf_common::get_gain( size_t chan ) -{ - return _amp_gain; -} - -std::vector< std::string > hackrf_common::get_antennas( size_t chan ) -{ - return { get_antenna( chan ) }; -} - -std::string hackrf_common::set_antenna( const std::string & antenna, size_t chan ) -{ - return get_antenna( chan ); -} - -std::string hackrf_common::get_antenna( size_t chan ) -{ - return "TX/RX"; -} - -double hackrf_common::set_bandwidth( double bandwidth, size_t chan ) -{ - int ret; -// osmosdr::freq_range_t bandwidths = get_bandwidth_range( chan ); - - _requested_bandwidth = bandwidth; - if ( bandwidth == 0.0 ) /* bandwidth of 0 means automatic filter selection */ - bandwidth = _sample_rate * 0.75; /* select narrower filters to prevent aliasing */ - - /* compute best default value depending on sample rate (auto filter) */ - uint32_t bw = hackrf_compute_baseband_filter_bw( uint32_t(bandwidth) ); - - if (_dev.get() && _started) { - ret = hackrf_set_baseband_filter_bandwidth( _dev.get(), bw ); - if (HACKRF_SUCCESS != ret) { - HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_baseband_filter_bandwidth", bw ) ) - } - } - - _bandwidth = bw; - return get_bandwidth(chan); -} - -double hackrf_common::get_bandwidth( size_t chan ) -{ - return _bandwidth; -} - -osmosdr::freq_range_t hackrf_common::get_bandwidth_range( size_t chan ) -{ - osmosdr::freq_range_t bandwidths; - - // TODO: read out from libhackrf when an API is available - - bandwidths.push_back(osmosdr::range_t( 1750000 )); - bandwidths.push_back(osmosdr::range_t( 2500000 )); - bandwidths.push_back(osmosdr::range_t( 3500000 )); - bandwidths.push_back(osmosdr::range_t( 5000000 )); - bandwidths.push_back(osmosdr::range_t( 5500000 )); - bandwidths.push_back(osmosdr::range_t( 6000000 )); - bandwidths.push_back(osmosdr::range_t( 7000000 )); - bandwidths.push_back(osmosdr::range_t( 8000000 )); - bandwidths.push_back(osmosdr::range_t( 9000000 )); - bandwidths.push_back(osmosdr::range_t( 10000000 )); - bandwidths.push_back(osmosdr::range_t( 12000000 )); - bandwidths.push_back(osmosdr::range_t( 14000000 )); - bandwidths.push_back(osmosdr::range_t( 15000000 )); - bandwidths.push_back(osmosdr::range_t( 20000000 )); - bandwidths.push_back(osmosdr::range_t( 24000000 )); - bandwidths.push_back(osmosdr::range_t( 28000000 )); - - return bandwidths; -} - -bool hackrf_common::set_bias( bool bias ) -{ - int ret; - - if (_dev.get() && _started) { - ret = hackrf_set_antenna_enable(_dev.get(), static_cast<uint8_t>(bias)); - if (ret != HACKRF_SUCCESS) - { - std::cerr << "Failed to apply antenna bias voltage state: " << bias << HACKRF_FORMAT_ERROR(ret, "") << std::endl; - } - } - - _bias = bias; - return get_bias(); -} - -bool hackrf_common::get_bias() -{ - return _bias; -} - -void hackrf_common::start() -{ - _started = true; - set_center_freq(get_center_freq()); - set_sample_rate(get_sample_rate()); - if (_requested_bandwidth != 0) - set_bandwidth(get_bandwidth()); - set_gain(get_gain()); - set_bias(get_bias()); -} - -void hackrf_common::stop() -{ - _started = false; -} diff --git a/lib/hackrf/hackrf_common.h b/lib/hackrf/hackrf_common.h deleted file mode 100644 index d1ab47b..0000000 --- a/lib/hackrf/hackrf_common.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2020 Clayton Smith <argilo@gmail.com> - * - * gr-osmosdr 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, or (at your option) - * any later version. - * - * gr-osmosdr 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 gr-osmosdr; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef INCLUDED_HACKRF_COMMON_H -#define INCLUDED_HACKRF_COMMON_H - -#include <map> -#include <memory> -#include <mutex> -#include <string> -#include <vector> - -#include <boost/format.hpp> - -#include <osmosdr/ranges.h> -#include <libhackrf/hackrf.h> - -#define BUF_LEN (16 * 32 * 512) /* must be multiple of 512 */ -#define BUF_NUM 15 - -#define BYTES_PER_SAMPLE 2 /* HackRF device produces/consumes 8 bit signed IQ data */ - -#define HACKRF_FORMAT_ERROR(ret, msg) \ - boost::str( boost::format(msg " (%1%) %2%") \ - % ret % hackrf_error_name((enum hackrf_error)ret) ) - -#define HACKRF_THROW_ON_ERROR(ret, msg) \ - if ( ret != HACKRF_SUCCESS ) \ - { \ - throw std::runtime_error( HACKRF_FORMAT_ERROR(ret, msg) ); \ - } - -#define HACKRF_FUNC_STR(func, arg) \ - boost::str(boost::format(func "(%1%)") % arg) + " has failed" - -typedef std::shared_ptr<hackrf_device> hackrf_sptr; - -class hackrf_common -{ -public: - hackrf_common(const std::string &args); - -protected: - static std::vector< std::string > get_devices(); - - osmosdr::meta_range_t get_sample_rates( void ); - double set_sample_rate( double rate ); - double get_sample_rate( void ); - - osmosdr::freq_range_t get_freq_range( size_t chan = 0 ); - double set_center_freq( double freq, size_t chan = 0 ); - double get_center_freq( size_t chan = 0 ); - double set_freq_corr( double ppm, size_t chan = 0 ); - double get_freq_corr( size_t chan = 0 ); - - bool set_gain_mode( bool automatic, size_t chan = 0 ); - bool get_gain_mode( size_t chan = 0 ); - double set_gain( double gain, size_t chan = 0 ); - double get_gain( size_t chan = 0 ); - - std::vector< std::string > get_antennas( size_t chan = 0 ); - std::string set_antenna( const std::string & antenna, size_t chan = 0 ); - std::string get_antenna( size_t chan = 0 ); - - double set_bandwidth( double bandwidth, size_t chan = 0 ); - double get_bandwidth( size_t chan = 0 ); - osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 ); - - bool set_bias( bool bias ); - bool get_bias(); - - void start(); - void stop(); - - hackrf_sptr _dev; - -private: - static void close(void *dev); - - static int _usage; - static std::mutex _usage_mutex; - - static std::map<std::string, std::weak_ptr<hackrf_device>> _devs; - static std::mutex _devs_mutex; - - double _sample_rate; - double _center_freq; - double _freq_corr; - bool _auto_gain; - double _amp_gain; - double _requested_bandwidth; - double _bandwidth; - bool _bias; - bool _started; -}; - -#endif /* INCLUDED_HACKRF_COMMON_H */ diff --git a/lib/hackrf/hackrf_sink_c.cc b/lib/hackrf/hackrf_sink_c.cc index 1762934..ee089c6 100644 --- a/lib/hackrf/hackrf_sink_c.cc +++ b/lib/hackrf/hackrf_sink_c.cc @@ -2,20 +2,19 @@ /* * Copyright 2013 Dimitri Stolnikov <horiz0n@gmx.net> * Copyright 2014 Hoernchen <la@tfc-server.de> - * Copyright 2020 Clayton Smith <argilo@gmail.com> * - * gr-osmosdr is free software; you can redistribute it and/or modify + * GNU Radio 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, or (at your option) * any later version. * - * gr-osmosdr is distributed in the hope that it will be useful, + * GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to + * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ @@ -38,12 +37,38 @@ #include <emmintrin.h> #endif +#include <boost/assign.hpp> +#include <boost/format.hpp> +#include <boost/detail/endian.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/thread/thread.hpp> + #include <gnuradio/io_signature.h> #include "hackrf_sink_c.h" #include "arg_helpers.h" +using namespace boost::assign; + +#define BUF_LEN (16 * 32 * 512) /* must be multiple of 512 */ +#define BUF_NUM 15 + +#define BYTES_PER_SAMPLE 2 /* HackRF device consumes 8 bit unsigned IQ data */ + +#define HACKRF_FORMAT_ERROR(ret, msg) \ + boost::str( boost::format(msg " (%1%) %2%") \ + % ret % hackrf_error_name((enum hackrf_error)ret) ) + +#define HACKRF_THROW_ON_ERROR(ret, msg) \ + if ( ret != HACKRF_SUCCESS ) \ + { \ + throw std::runtime_error( HACKRF_FORMAT_ERROR(ret, msg) ); \ + } + +#define HACKRF_FUNC_STR(func, arg) \ + boost::str(boost::format(func "(%1%)") % arg) + " has failed" + static inline bool cb_init(circular_buffer_t *cb, size_t capacity, size_t sz) { cb->buffer = malloc(capacity * sz); @@ -78,11 +103,6 @@ static inline bool cb_has_room(circular_buffer_t *cb) return true; } -static inline bool cb_is_empty(circular_buffer_t *cb) -{ - return cb->count == 0; -} - static inline bool cb_push_back(circular_buffer_t *cb, const void *item) { if(cb->count == cb->capacity) @@ -107,6 +127,9 @@ static inline bool cb_pop_front(circular_buffer_t *cb, void *item) return true; } +int hackrf_sink_c::_usage = 0; +boost::mutex hackrf_sink_c::_usage_mutex; + hackrf_sink_c_sptr make_hackrf_sink_c (const std::string & args) { return gnuradio::get_initial_sptr(new hackrf_sink_c (args)); @@ -133,21 +156,66 @@ hackrf_sink_c::hackrf_sink_c (const std::string &args) : gr::sync_block ("hackrf_sink_c", gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)), gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))), - hackrf_common::hackrf_common(args), + _dev(NULL), _buf(NULL), - _vga_gain(0) + _sample_rate(0), + _center_freq(0), + _freq_corr(0), + _auto_gain(false), + _amp_gain(0), + _vga_gain(0), + _bandwidth(0) { + int ret; + std::string *hackrf_serial = NULL; + dict_t dict = params_to_dict(args); + if (dict.count("hackrf") && dict["hackrf"].length() > 0) + hackrf_serial = &dict["hackrf"]; + _buf_num = 0; if (dict.count("buffers")) - _buf_num = std::stoi(dict["buffers"]); + _buf_num = boost::lexical_cast< unsigned int >( dict["buffers"] ); if (0 == _buf_num) _buf_num = BUF_NUM; - _stopping = false; + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + if ( _usage == 0 ) + hackrf_init(); /* call only once before the first open */ + + _usage++; + } + + _dev = NULL; +#ifdef LIBHACKRF_HAVE_DEVICE_LIST + if ( hackrf_serial ) + ret = hackrf_open_by_serial( hackrf_serial->c_str(), &_dev ); + else +#endif + ret = hackrf_open( &_dev ); + HACKRF_THROW_ON_ERROR(ret, "Failed to open HackRF device") + + uint8_t board_id; + ret = hackrf_board_id_read( _dev, &board_id ); + HACKRF_THROW_ON_ERROR(ret, "Failed to get HackRF board id") + + char version[40]; + memset(version, 0, sizeof(version)); + ret = hackrf_version_string_read( _dev, version, sizeof(version)); + HACKRF_THROW_ON_ERROR(ret, "Failed to read version string") +#if 0 + read_partid_serialno_t serial_number; + ret = hackrf_board_partid_serialno_read( _dev, &serial_number ); + HACKRF_THROW_ON_ERROR(ret, "Failed to read serial number") +#endif + std::cerr << "Using " << hackrf_board_id_name(hackrf_board_id(board_id)) << " " + << "with firmware " << version << " " + << std::endl; if ( BUF_NUM != _buf_num ) { std::cerr << "Using " << _buf_num << " buffers of size " << BUF_LEN << "." @@ -164,12 +232,26 @@ hackrf_sink_c::hackrf_sink_c (const std::string &args) // Check device args to find out if bias/phantom power is desired. if ( dict.count("bias_tx") ) { - hackrf_common::set_bias(dict["bias_tx"] == "1"); + bool bias = boost::lexical_cast<bool>( dict["bias_tx"] ); + ret = hackrf_set_antenna_enable(_dev, static_cast<uint8_t>(bias)); + if ( ret != HACKRF_SUCCESS ) + { + std::cerr << "Failed to apply antenna bias voltage state: " << bias << HACKRF_FORMAT_ERROR(ret, "") << std::endl; + } + else + { + std::cerr << (bias ? "Enabled" : "Disabled") << " antenna bias voltage" << std::endl; + } } _buf = (int8_t *) malloc( BUF_LEN ); cb_init( &_cbuf, _buf_num, BUF_LEN ); + +// _thread = gr::thread::thread(_hackrf_wait, this); + + ret = hackrf_start_tx( _dev, _hackrf_tx_callback, (void *)this ); + HACKRF_THROW_ON_ERROR(ret, "Failed to start TX streaming") } /* @@ -177,6 +259,30 @@ hackrf_sink_c::hackrf_sink_c (const std::string &args) */ hackrf_sink_c::~hackrf_sink_c () { + if (_dev) { +// _thread.join(); + int ret = hackrf_stop_tx( _dev ); + if ( ret != HACKRF_SUCCESS ) + { + std::cerr << HACKRF_FORMAT_ERROR(ret, "Failed to stop TX streaming") << std::endl; + } + ret = hackrf_close( _dev ); + if ( ret != HACKRF_SUCCESS ) + { + std::cerr << HACKRF_FORMAT_ERROR(ret, "Failed to close HackRF") << std::endl; + } + _dev = NULL; + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + _usage--; + + if ( _usage == 0 ) + hackrf_exit(); /* call only once after last close */ + } + } + free(_buf); _buf = NULL; @@ -196,16 +302,11 @@ int hackrf_sink_c::hackrf_tx_callback(unsigned char *buffer, uint32_t length) *buffer++ = rand() % 255; #else { - std::lock_guard<std::mutex> lock(_buf_mutex); + boost::mutex::scoped_lock lock( _buf_mutex ); if ( ! cb_pop_front( &_cbuf, buffer ) ) { memset(buffer, 0, length); - if (_stopping) { - _buf_cond.notify_one(); - return -1; - } else { - std::cerr << "U" << std::flush; - } + std::cerr << "U" << std::flush; } else { // std::cerr << "-" << std::flush; _buf_cond.notify_one(); @@ -215,61 +316,42 @@ int hackrf_sink_c::hackrf_tx_callback(unsigned char *buffer, uint32_t length) return 0; // TODO: return -1 on error/stop } +void hackrf_sink_c::_hackrf_wait(hackrf_sink_c *obj) +{ + obj->hackrf_wait(); +} + +void hackrf_sink_c::hackrf_wait() +{ +} + bool hackrf_sink_c::start() { - if ( ! _dev.get() ) + if ( ! _dev ) return false; - _stopping = false; _buf_used = 0; - hackrf_common::start(); - int ret = hackrf_start_tx( _dev.get(), _hackrf_tx_callback, (void *)this ); +#if 0 + int ret = hackrf_start_tx( _dev, _hackrf_tx_callback, (void *)this ); if ( ret != HACKRF_SUCCESS ) { std::cerr << "Failed to start TX streaming (" << ret << ")" << std::endl; return false; } +#endif return true; } bool hackrf_sink_c::stop() { - int i; - - if ( ! _dev.get() ) + if ( ! _dev ) return false; - - { - std::unique_lock<std::mutex> lock(_buf_mutex); - - while ( ! cb_has_room(&_cbuf) ) - _buf_cond.wait( lock ); - - // Fill the rest of the current buffer with silence. - memset(_buf + _buf_used, 0, BUF_LEN - _buf_used); - cb_push_back( &_cbuf, _buf ); - _buf_used = 0; - - // Add some more silence so the end doesn't get cut off. - memset(_buf, 0, BUF_LEN); - for (i = 0; i < 5; i++) { - while ( ! cb_has_room(&_cbuf) ) - _buf_cond.wait( lock ); - - cb_push_back( &_cbuf, _buf ); - } - - _stopping = true; - - while (hackrf_is_streaming(_dev.get()) == HACKRF_TRUE) - _buf_cond.wait( lock ); - } - - hackrf_common::stop(); - int ret = hackrf_stop_tx( _dev.get() ); +#if 0 + int ret = hackrf_stop_tx( _dev ); if ( ret != HACKRF_SUCCESS ) { std::cerr << "Failed to stop TX streaming (" << ret << ")" << std::endl; return false; } +#endif return true; } @@ -342,7 +424,7 @@ int hackrf_sink_c::work( int noutput_items, const gr_complex *in = (const gr_complex *) input_items[0]; { - std::unique_lock<std::mutex> lock(_buf_mutex); + boost::mutex::scoped_lock lock( _buf_mutex ); while ( ! cb_has_room(&_cbuf) ) _buf_cond.wait( lock ); @@ -372,7 +454,7 @@ int hackrf_sink_c::work( int noutput_items, if((unsigned int)noutput_items >= remaining) { { - std::lock_guard<std::mutex> lock(_buf_mutex); + boost::mutex::scoped_lock lock( _buf_mutex ); if ( ! cb_push_back( &_cbuf, _buf ) ) { _buf_used = prev_buf_used; @@ -395,7 +477,78 @@ int hackrf_sink_c::work( int noutput_items, std::vector<std::string> hackrf_sink_c::get_devices() { - return hackrf_common::get_devices(); + std::vector<std::string> devices; + std::string label; + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + if ( _usage == 0 ) + hackrf_init(); /* call only once before the first open */ + + _usage++; + } + +#ifdef LIBHACKRF_HAVE_DEVICE_LIST + hackrf_device_list_t *list = hackrf_device_list(); + + for (int i = 0; i < list->devicecount; i++) { + label = "HackRF "; + label += hackrf_usb_board_id_name( list->usb_board_ids[i] ); + + std::string args; + if (list->serial_numbers[i]) { + std::string serial = boost::lexical_cast< std::string >( list->serial_numbers[i] ); + if (serial.length() > 6) + serial = serial.substr(serial.length() - 6, 6); + args = "hackrf=" + serial; + label += " " + serial; + } else + args = "hackrf"; /* will pick the first one, serial number is required for choosing a specific one */ + + boost::algorithm::trim(label); + + args += ",label='" + label + "'"; + devices.push_back( args ); + } + + hackrf_device_list_free(list); +#else + + int ret; + hackrf_device *dev = NULL; + ret = hackrf_open(&dev); + if ( HACKRF_SUCCESS == ret ) + { + std::string args = "hackrf=0"; + + label = "HackRF"; + + uint8_t board_id; + ret = hackrf_board_id_read( dev, &board_id ); + if ( HACKRF_SUCCESS == ret ) + { + label += std::string(" ") + hackrf_board_id_name(hackrf_board_id(board_id)); + } + + args += ",label='" + label + "'"; + devices.push_back( args ); + + ret = hackrf_close(dev); + } + +#endif + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + _usage--; + + if ( _usage == 0 ) + hackrf_exit(); /* call only once after last close */ + } + + return devices; } size_t hackrf_sink_c::get_num_channels() @@ -405,47 +558,98 @@ size_t hackrf_sink_c::get_num_channels() osmosdr::meta_range_t hackrf_sink_c::get_sample_rates() { - return hackrf_common::get_sample_rates(); + osmosdr::meta_range_t range; + + /* we only add integer rates here because of better phase noise performance. + * the user is allowed to request arbitrary (fractional) rates within these + * boundaries. */ + + range += osmosdr::range_t( 8e6 ); + range += osmosdr::range_t( 10e6 ); + range += osmosdr::range_t( 12.5e6 ); + range += osmosdr::range_t( 16e6 ); + range += osmosdr::range_t( 20e6 ); /* confirmed to work on fast machines */ + + return range; } double hackrf_sink_c::set_sample_rate( double rate ) { - return hackrf_common::set_sample_rate(rate); + int ret; + + if (_dev) { + ret = hackrf_set_sample_rate( _dev, rate ); + if ( HACKRF_SUCCESS == ret ) { + _sample_rate = rate; + //set_bandwidth( 0.0 ); /* bandwidth of 0 means automatic filter selection */ + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_sample_rate", rate ) ) + } + } + + return get_sample_rate(); } double hackrf_sink_c::get_sample_rate() { - return hackrf_common::get_sample_rate(); + return _sample_rate; } osmosdr::freq_range_t hackrf_sink_c::get_freq_range( size_t chan ) { - return hackrf_common::get_freq_range(chan); + osmosdr::freq_range_t range; + + range += osmosdr::range_t( _sample_rate / 2, 7250e6 - _sample_rate / 2 ); + + return range; } double hackrf_sink_c::set_center_freq( double freq, size_t chan ) { - return hackrf_common::set_center_freq(freq, chan); + int ret; + + #define APPLY_PPM_CORR(val, ppm) ((val) * (1.0 + (ppm) * 0.000001)) + + if (_dev) { + double corr_freq = APPLY_PPM_CORR( freq, _freq_corr ); + ret = hackrf_set_freq( _dev, uint64_t(corr_freq) ); + if ( HACKRF_SUCCESS == ret ) { + _center_freq = freq; + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_freq", corr_freq ) ) + } + } + + return get_center_freq( chan ); } double hackrf_sink_c::get_center_freq( size_t chan ) { - return hackrf_common::get_center_freq(chan); + return _center_freq; } double hackrf_sink_c::set_freq_corr( double ppm, size_t chan ) { - return hackrf_common::set_freq_corr(ppm, chan); + _freq_corr = ppm; + + set_center_freq( _center_freq ); + + return get_freq_corr( chan ); } double hackrf_sink_c::get_freq_corr( size_t chan ) { - return hackrf_common::get_freq_corr(chan); + return _freq_corr; } std::vector<std::string> hackrf_sink_c::get_gain_names( size_t chan ) { - return { "RF", "IF" }; + std::vector< std::string > names; + + names += "RF"; + names += "IF"; + + return names; } osmosdr::gain_range_t hackrf_sink_c::get_gain_range( size_t chan ) @@ -468,17 +672,34 @@ osmosdr::gain_range_t hackrf_sink_c::get_gain_range( const std::string & name, s bool hackrf_sink_c::set_gain_mode( bool automatic, size_t chan ) { - return hackrf_common::set_gain_mode(automatic, chan); + _auto_gain = automatic; + + return get_gain_mode(chan); } bool hackrf_sink_c::get_gain_mode( size_t chan ) { - return hackrf_common::get_gain_mode(chan); + return _auto_gain; } double hackrf_sink_c::set_gain( double gain, size_t chan ) { - return hackrf_common::set_gain(gain, chan); + int ret; + osmosdr::gain_range_t rf_gains = get_gain_range( "RF", chan ); + + if (_dev) { + double clip_gain = rf_gains.clip( gain, true ); + uint8_t value = clip_gain == 14.0f ? 1 : 0; + + ret = hackrf_set_amp_enable( _dev, value ); + if ( HACKRF_SUCCESS == ret ) { + _amp_gain = clip_gain; + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_amp_enable", value ) ) + } + } + + return _amp_gain; } double hackrf_sink_c::set_gain( double gain, const std::string & name, size_t chan) @@ -496,7 +717,7 @@ double hackrf_sink_c::set_gain( double gain, const std::string & name, size_t ch double hackrf_sink_c::get_gain( size_t chan ) { - return hackrf_common::get_gain(chan); + return _amp_gain; } double hackrf_sink_c::get_gain( const std::string & name, size_t chan ) @@ -517,10 +738,10 @@ double hackrf_sink_c::set_if_gain( double gain, size_t chan ) int ret; osmosdr::gain_range_t if_gains = get_gain_range( "IF", chan ); - if (_dev.get()) { + if (_dev) { double clip_gain = if_gains.clip( gain, true ); - ret = hackrf_set_txvga_gain( _dev.get(), uint32_t(clip_gain) ); + ret = hackrf_set_txvga_gain( _dev, uint32_t(clip_gain) ); if ( HACKRF_SUCCESS == ret ) { _vga_gain = clip_gain; } else { @@ -538,30 +759,72 @@ double hackrf_sink_c::set_bb_gain( double gain, size_t chan ) std::vector< std::string > hackrf_sink_c::get_antennas( size_t chan ) { - return hackrf_common::get_antennas(chan); + std::vector< std::string > antennas; + + antennas += get_antenna( chan ); + + return antennas; } std::string hackrf_sink_c::set_antenna( const std::string & antenna, size_t chan ) { - return hackrf_common::set_antenna(antenna, chan); + return get_antenna( chan ); } std::string hackrf_sink_c::get_antenna( size_t chan ) { - return hackrf_common::get_antenna(chan); + return "TX/RX"; } double hackrf_sink_c::set_bandwidth( double bandwidth, size_t chan ) { - return hackrf_common::set_bandwidth(bandwidth, chan); + int ret; +// osmosdr::freq_range_t bandwidths = get_bandwidth_range( chan ); + + if ( bandwidth == 0.0 ) /* bandwidth of 0 means automatic filter selection */ + bandwidth = _sample_rate * 0.75; /* select narrower filters to prevent aliasing */ + + if ( _dev ) { + /* compute best default value depending on sample rate (auto filter) */ + uint32_t bw = hackrf_compute_baseband_filter_bw( uint32_t(bandwidth) ); + ret = hackrf_set_baseband_filter_bandwidth( _dev, bw ); + if ( HACKRF_SUCCESS == ret ) { + _bandwidth = bw; + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_baseband_filter_bandwidth", bw ) ) + } + } + + return _bandwidth; } double hackrf_sink_c::get_bandwidth( size_t chan ) { - return hackrf_common::get_bandwidth(chan); + return _bandwidth; } osmosdr::freq_range_t hackrf_sink_c::get_bandwidth_range( size_t chan ) { - return hackrf_common::get_bandwidth_range(chan); + osmosdr::freq_range_t bandwidths; + + // TODO: read out from libhackrf when an API is available + + bandwidths += osmosdr::range_t( 1750000 ); + bandwidths += osmosdr::range_t( 2500000 ); + bandwidths += osmosdr::range_t( 3500000 ); + bandwidths += osmosdr::range_t( 5000000 ); + bandwidths += osmosdr::range_t( 5500000 ); + bandwidths += osmosdr::range_t( 6000000 ); + bandwidths += osmosdr::range_t( 7000000 ); + bandwidths += osmosdr::range_t( 8000000 ); + bandwidths += osmosdr::range_t( 9000000 ); + bandwidths += osmosdr::range_t( 10000000 ); + bandwidths += osmosdr::range_t( 12000000 ); + bandwidths += osmosdr::range_t( 14000000 ); + bandwidths += osmosdr::range_t( 15000000 ); + bandwidths += osmosdr::range_t( 20000000 ); + bandwidths += osmosdr::range_t( 24000000 ); + bandwidths += osmosdr::range_t( 28000000 ); + + return bandwidths; } diff --git a/lib/hackrf/hackrf_sink_c.h b/lib/hackrf/hackrf_sink_c.h index 08ff2ca..a7e7ab8 100644 --- a/lib/hackrf/hackrf_sink_c.h +++ b/lib/hackrf/hackrf_sink_c.h @@ -1,35 +1,34 @@ /* -*- c++ -*- */ /* * Copyright 2013 Dimitri Stolnikov <horiz0n@gmx.net> - * Copyright 2020 Clayton Smith <argilo@gmail.com> * - * gr-osmosdr is free software; you can redistribute it and/or modify + * GNU Radio 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, or (at your option) * any later version. * - * gr-osmosdr is distributed in the hope that it will be useful, + * GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to + * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef INCLUDED_HACKRF_SINK_C_H #define INCLUDED_HACKRF_SINK_C_H +#include <gnuradio/thread/thread.h> #include <gnuradio/sync_block.h> -#include <condition_variable> -#include <mutex> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include <libhackrf/hackrf.h> #include "sink_iface.h" -#include "hackrf_common.h" class hackrf_sink_c; @@ -68,8 +67,7 @@ hackrf_sink_c_sptr make_hackrf_sink_c (const std::string & args = ""); class hackrf_sink_c : public gr::sync_block, - public sink_iface, - protected hackrf_common + public sink_iface { private: // The friend declaration allows hackrf_make_sink_c to @@ -126,16 +124,29 @@ public: private: static int _hackrf_tx_callback(hackrf_transfer* transfer); int hackrf_tx_callback(unsigned char *buffer, uint32_t length); + static void _hackrf_wait(hackrf_sink_c *obj); + void hackrf_wait(); + + static int _usage; + static boost::mutex _usage_mutex; + + hackrf_device *_dev; +// gr::thread::thread _thread; circular_buffer_t _cbuf; int8_t *_buf; unsigned int _buf_num; unsigned int _buf_used; - bool _stopping; - std::mutex _buf_mutex; - std::condition_variable _buf_cond; - + boost::mutex _buf_mutex; + boost::condition_variable _buf_cond; + + double _sample_rate; + double _center_freq; + double _freq_corr; + bool _auto_gain; + double _amp_gain; double _vga_gain; + double _bandwidth; }; #endif /* INCLUDED_HACKRF_SINK_C_H */ diff --git a/lib/hackrf/hackrf_source_c.cc b/lib/hackrf/hackrf_source_c.cc index 03ea3bd..30b63c7 100644 --- a/lib/hackrf/hackrf_source_c.cc +++ b/lib/hackrf/hackrf_source_c.cc @@ -1,20 +1,19 @@ /* -*- c++ -*- */ /* * Copyright 2013 Dimitri Stolnikov <horiz0n@gmx.net> - * Copyright 2020 Clayton Smith <argilo@gmail.com> * - * gr-osmosdr is free software; you can redistribute it and/or modify + * GNU Radio 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, or (at your option) * any later version. * - * gr-osmosdr is distributed in the hope that it will be useful, + * GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to + * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ @@ -30,7 +29,12 @@ #include <stdexcept> #include <iostream> -#include <chrono> + +#include <boost/assign.hpp> +#include <boost/format.hpp> +#include <boost/detail/endian.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/thread/thread.hpp> #include <gnuradio/io_signature.h> @@ -38,6 +42,29 @@ #include "arg_helpers.h" +using namespace boost::assign; + +#define BUF_LEN (16 * 32 * 512) /* must be multiple of 512 */ +#define BUF_NUM 15 + +#define BYTES_PER_SAMPLE 2 /* HackRF device produces 8 bit unsigned IQ data */ + +#define HACKRF_FORMAT_ERROR(ret, msg) \ + boost::str( boost::format(msg " (%1%) %2%") \ + % ret % hackrf_error_name((enum hackrf_error)ret) ) + +#define HACKRF_THROW_ON_ERROR(ret, msg) \ + if ( ret != HACKRF_SUCCESS ) \ + { \ + throw std::runtime_error( HACKRF_FORMAT_ERROR(ret, msg) ); \ + } + +#define HACKRF_FUNC_STR(func, arg) \ + boost::str(boost::format(func "(%1%)") % arg) + " has failed" + +int hackrf_source_c::_usage = 0; +boost::mutex hackrf_source_c::_usage_mutex; + hackrf_source_c_sptr make_hackrf_source_c (const std::string & args) { return gnuradio::get_initial_sptr(new hackrf_source_c (args)); @@ -64,20 +91,29 @@ hackrf_source_c::hackrf_source_c (const std::string &args) : gr::sync_block ("hackrf_source_c", gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)), gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))), - hackrf_common::hackrf_common(args), + _dev(NULL), _buf(NULL), + _sample_rate(0), + _center_freq(0), + _freq_corr(0), + _auto_gain(false), + _amp_gain(0), _lna_gain(0), - _vga_gain(0) + _vga_gain(0), + _bandwidth(0) { + int ret; + std::string hackrf_serial; + dict_t dict = params_to_dict(args); _buf_num = _buf_len = _buf_head = _buf_used = _buf_offset = 0; if (dict.count("buffers")) - _buf_num = std::stoi(dict["buffers"]); + _buf_num = boost::lexical_cast< unsigned int >( dict["buffers"] ); // if (dict.count("buflen")) -// _buf_len = std::stoi(dict["buflen"]); +// _buf_len = boost::lexical_cast< unsigned int >( dict["buflen"] ); if (0 == _buf_num) _buf_num = BUF_NUM; @@ -88,10 +124,76 @@ hackrf_source_c::hackrf_source_c (const std::string &args) _samp_avail = _buf_len / BYTES_PER_SAMPLE; // create a lookup table for gr_complex values - for (unsigned int i = 0; i <= 0xff; i++) { - _lut.push_back( float(int8_t(i)) * (1.0f/128.0f) ); + for (unsigned int i = 0; i <= 0xffff; i++) { +#ifdef BOOST_LITTLE_ENDIAN + _lut.push_back( gr_complex( (float(int8_t(i & 0xff))) * (1.0f/128.0f), + (float(int8_t(i >> 8))) * (1.0f/128.0f) ) ); +#else // BOOST_BIG_ENDIAN + _lut.push_back( gr_complex( (float(int8_t(i >> 8))) * (1.0f/128.0f), + (float(int8_t(i & 0xff))) * (1.0f/128.0f) ) ); +#endif + } + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + if ( _usage == 0 ) + hackrf_init(); /* call only once before the first open */ + + _usage++; } + _dev = NULL; + +#ifdef LIBHACKRF_HAVE_DEVICE_LIST + if (dict.count("hackrf") && dict["hackrf"].length() > 0) { + hackrf_serial = dict["hackrf"]; + + if (hackrf_serial.length() > 1) { + ret = hackrf_open_by_serial( hackrf_serial.c_str(), &_dev ); + } else { + int dev_index = 0; + try { + dev_index = boost::lexical_cast< int >( hackrf_serial ); + } catch ( std::exception &ex ) { + throw std::runtime_error( + "Failed to use '" + hackrf_serial + "' as HackRF device index number: " + ex.what()); + } + + hackrf_device_list_t *list = hackrf_device_list(); + if (dev_index < list->devicecount) { + ret = hackrf_device_list_open(list, dev_index, &_dev); + } else { + hackrf_device_list_free(list); + throw std::runtime_error( + "Failed to use '" + hackrf_serial + "' as HackRF device index: not enough devices"); + } + hackrf_device_list_free(list); + } + } else +#endif + ret = hackrf_open( &_dev ); + + HACKRF_THROW_ON_ERROR(ret, "Failed to open HackRF device") + + uint8_t board_id; + ret = hackrf_board_id_read( _dev, &board_id ); + HACKRF_THROW_ON_ERROR(ret, "Failed to get HackRF board id") + + char version[40]; + memset(version, 0, sizeof(version)); + ret = hackrf_version_string_read( _dev, version, sizeof(version)); + HACKRF_THROW_ON_ERROR(ret, "Failed to read version string") + +#if 0 + read_partid_serialno_t serial_number; + ret = hackrf_board_partid_serialno_read( _dev, &serial_number ); + HACKRF_THROW_ON_ERROR(ret, "Failed to read serial number") +#endif + std::cerr << "Using " << hackrf_board_id_name(hackrf_board_id(board_id)) << " " + << "with firmware " << version << " " + << std::endl; + if ( BUF_NUM != _buf_num || BUF_LEN != _buf_len ) { std::cerr << "Using " << _buf_num << " buffers of size " << _buf_len << "." << std::endl; @@ -109,15 +211,29 @@ hackrf_source_c::hackrf_source_c (const std::string &args) // Check device args to find out if bias/phantom power is desired. if ( dict.count("bias") ) { - hackrf_common::set_bias(dict["bias"] == "1"); + bool bias = boost::lexical_cast<bool>( dict["bias"] ); + ret = hackrf_set_antenna_enable(_dev, static_cast<uint8_t>(bias)); + if ( ret != HACKRF_SUCCESS ) + { + std::cerr << "Failed to apply antenna bias voltage state: " << bias << HACKRF_FORMAT_ERROR(ret, "") << std::endl; + } + else + { + std::cerr << (bias ? "Enabled" : "Disabled") << " antenna bias voltage" << std::endl; + } } - _buf = (unsigned char **) malloc(_buf_num * sizeof(unsigned char *)); + _buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *)); if (_buf) { for(unsigned int i = 0; i < _buf_num; ++i) - _buf[i] = (unsigned char *) malloc(_buf_len); + _buf[i] = (unsigned short *) malloc(_buf_len); } + +// _thread = gr::thread::thread(_hackrf_wait, this); + + ret = hackrf_start_rx( _dev, _hackrf_rx_callback, (void *)this ); + HACKRF_THROW_ON_ERROR(ret, "Failed to start RX streaming") } /* @@ -125,6 +241,30 @@ hackrf_source_c::hackrf_source_c (const std::string &args) */ hackrf_source_c::~hackrf_source_c () { + if (_dev) { +// _thread.join(); + int ret = hackrf_stop_rx( _dev ); + if ( ret != HACKRF_SUCCESS ) + { + std::cerr << HACKRF_FORMAT_ERROR(ret, "Failed to stop RX streaming") << std::endl; + } + ret = hackrf_close( _dev ); + if ( ret != HACKRF_SUCCESS ) + { + std::cerr << HACKRF_FORMAT_ERROR(ret, "Failed to close HackRF") << std::endl; + } + _dev = NULL; + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + _usage--; + + if ( _usage == 0 ) + hackrf_exit(); /* call only once after last close */ + } + } + if (_buf) { for(unsigned int i = 0; i < _buf_num; ++i) { free(_buf[i]); @@ -144,7 +284,7 @@ int hackrf_source_c::_hackrf_rx_callback(hackrf_transfer *transfer) int hackrf_source_c::hackrf_rx_callback(unsigned char *buf, uint32_t len) { { - std::lock_guard<std::mutex> lock(_buf_mutex); + boost::mutex::scoped_lock lock( _buf_mutex ); int buf_tail = (_buf_head + _buf_used) % _buf_num; memcpy(_buf[buf_tail], buf, len); @@ -162,31 +302,40 @@ int hackrf_source_c::hackrf_rx_callback(unsigned char *buf, uint32_t len) return 0; // TODO: return -1 on error/stop } +void hackrf_source_c::_hackrf_wait(hackrf_source_c *obj) +{ + obj->hackrf_wait(); +} + +void hackrf_source_c::hackrf_wait() +{ +} + bool hackrf_source_c::start() { - if ( ! _dev.get() ) + if ( ! _dev ) return false; - - hackrf_common::start(); - int ret = hackrf_start_rx( _dev.get(), _hackrf_rx_callback, (void *)this ); +#if 0 + int ret = hackrf_start_rx( _dev, _hackrf_rx_callback, (void *)this ); if ( ret != HACKRF_SUCCESS ) { std::cerr << "Failed to start RX streaming (" << ret << ")" << std::endl; return false; } +#endif return true; } bool hackrf_source_c::stop() { - if ( ! _dev.get() ) + if ( ! _dev ) return false; - - hackrf_common::stop(); - int ret = hackrf_stop_rx( _dev.get() ); +#if 0 + int ret = hackrf_stop_rx( _dev ); if ( ret != HACKRF_SUCCESS ) { std::cerr << "Failed to stop RX streaming (" << ret << ")" << std::endl; return false; } +#endif return true; } @@ -198,41 +347,33 @@ int hackrf_source_c::work( int noutput_items, bool running = false; - if ( _dev.get() ) - running = (hackrf_is_streaming( _dev.get() ) == HACKRF_TRUE); + if ( _dev ) + running = (hackrf_is_streaming( _dev ) == HACKRF_TRUE); { - std::unique_lock<std::mutex> lock(_buf_mutex); + boost::mutex::scoped_lock lock( _buf_mutex ); - while (_buf_used < 3 && running) { // collect at least 3 buffers - _buf_cond.wait_for( lock , std::chrono::milliseconds(100)); - - // Re-check whether the device has closed or stopped streaming - if ( _dev.get() ) - running = (hackrf_is_streaming( _dev.get() ) == HACKRF_TRUE); - else - running = false; - } + while (_buf_used < 3 && running) // collect at least 3 buffers + _buf_cond.wait( lock ); } if ( ! running ) return WORK_DONE; - const uint8_t *buf = _buf[_buf_head] + _buf_offset * BYTES_PER_SAMPLE; -#define TO_COMPLEX(p) gr_complex( _lut[(p)[0]], _lut[(p)[1]] ) + unsigned short *buf = _buf[_buf_head] + _buf_offset; if (noutput_items <= _samp_avail) { for (int i = 0; i < noutput_items; ++i) - *out++ = TO_COMPLEX( buf + i*BYTES_PER_SAMPLE ); + *out++ = _lut[ *(buf + i) ]; _buf_offset += noutput_items; _samp_avail -= noutput_items; } else { for (int i = 0; i < _samp_avail; ++i) - *out++ = TO_COMPLEX( buf + i*BYTES_PER_SAMPLE ); + *out++ = _lut[ *(buf + i) ]; { - std::lock_guard<std::mutex> lock(_buf_mutex); + boost::mutex::scoped_lock lock( _buf_mutex ); _buf_head = (_buf_head + 1) % _buf_num; _buf_used--; @@ -243,7 +384,7 @@ int hackrf_source_c::work( int noutput_items, int remaining = noutput_items - _samp_avail; for (int i = 0; i < remaining; ++i) - *out++ = TO_COMPLEX( buf + i*BYTES_PER_SAMPLE ); + *out++ = _lut[ *(buf + i) ]; _buf_offset = remaining; _samp_avail = (_buf_len / BYTES_PER_SAMPLE) - remaining; @@ -254,7 +395,78 @@ int hackrf_source_c::work( int noutput_items, std::vector<std::string> hackrf_source_c::get_devices() { - return hackrf_common::get_devices(); + std::vector<std::string> devices; + std::string label; + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + if ( _usage == 0 ) + hackrf_init(); /* call only once before the first open */ + + _usage++; + } + +#ifdef LIBHACKRF_HAVE_DEVICE_LIST + hackrf_device_list_t *list = hackrf_device_list(); + + for (int i = 0; i < list->devicecount; i++) { + label = "HackRF "; + label += hackrf_usb_board_id_name( list->usb_board_ids[i] ); + + std::string args; + if (list->serial_numbers[i]) { + std::string serial = boost::lexical_cast< std::string >( list->serial_numbers[i] ); + if (serial.length() > 6) + serial = serial.substr(serial.length() - 6, 6); + args = "hackrf=" + serial; + label += " " + serial; + } else + args = "hackrf"; /* will pick the first one, serial number is required for choosing a specific one */ + + boost::algorithm::trim(label); + + args += ",label='" + label + "'"; + devices.push_back( args ); + } + + hackrf_device_list_free(list); +#else + + int ret; + hackrf_device *dev = NULL; + ret = hackrf_open(&dev); + if ( HACKRF_SUCCESS == ret ) + { + std::string args = "hackrf=0"; + + label = "HackRF"; + + uint8_t board_id; + ret = hackrf_board_id_read( dev, &board_id ); + if ( HACKRF_SUCCESS == ret ) + { + label += std::string(" ") + hackrf_board_id_name(hackrf_board_id(board_id)); + } + + args += ",label='" + label + "'"; + devices.push_back( args ); + + ret = hackrf_close(dev); + } + +#endif + + { + boost::mutex::scoped_lock lock( _usage_mutex ); + + _usage--; + + if ( _usage == 0 ) + hackrf_exit(); /* call only once after last close */ + } + + return devices; } size_t hackrf_source_c::get_num_channels() @@ -264,47 +476,99 @@ size_t hackrf_source_c::get_num_channels() osmosdr::meta_range_t hackrf_source_c::get_sample_rates() { - return hackrf_common::get_sample_rates(); + osmosdr::meta_range_t range; + + /* we only add integer rates here because of better phase noise performance. + * the user is allowed to request arbitrary (fractional) rates within these + * boundaries. */ + + range += osmosdr::range_t( 8e6 ); + range += osmosdr::range_t( 10e6 ); + range += osmosdr::range_t( 12.5e6 ); + range += osmosdr::range_t( 16e6 ); + range += osmosdr::range_t( 20e6 ); /* confirmed to work on fast machines */ + + return range; } double hackrf_source_c::set_sample_rate( double rate ) { - return hackrf_common::set_sample_rate(rate); + int ret; + + if (_dev) { + ret = hackrf_set_sample_rate( _dev, rate ); + if ( HACKRF_SUCCESS == ret ) { + _sample_rate = rate; + //set_bandwidth( 0.0 ); /* bandwidth of 0 means automatic filter selection */ + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_sample_rate", rate ) ) + } + } + + return get_sample_rate(); } double hackrf_source_c::get_sample_rate() { - return hackrf_common::get_sample_rate(); + return _sample_rate; } osmosdr::freq_range_t hackrf_source_c::get_freq_range( size_t chan ) { - return hackrf_common::get_freq_range(chan); + osmosdr::freq_range_t range; + + range += osmosdr::range_t( _sample_rate / 2, 7250e6 - _sample_rate / 2 ); + + return range; } double hackrf_source_c::set_center_freq( double freq, size_t chan ) { - return hackrf_common::set_center_freq(freq, chan); + int ret; + + #define APPLY_PPM_CORR(val, ppm) ((val) * (1.0 + (ppm) * 0.000001)) + + if (_dev) { + double corr_freq = APPLY_PPM_CORR( freq, _freq_corr ); + ret = hackrf_set_freq( _dev, uint64_t(corr_freq) ); + if ( HACKRF_SUCCESS == ret ) { + _center_freq = freq; + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_freq", corr_freq ) ) + } + } + + return get_center_freq( chan ); } double hackrf_source_c::get_center_freq( size_t chan ) { - return hackrf_common::get_center_freq(chan); + return _center_freq; } double hackrf_source_c::set_freq_corr( double ppm, size_t chan ) { - return hackrf_common::set_freq_corr(ppm, chan); + _freq_corr = ppm; + + set_center_freq( _center_freq ); + + return get_freq_corr( chan ); } double hackrf_source_c::get_freq_corr( size_t chan ) { - return hackrf_common::get_freq_corr(chan); + return _freq_corr; } std::vector<std::string> hackrf_source_c::get_gain_names( size_t chan ) { - return { "RF", "IF", "BB" }; + std::vector< std::string > names; + + names += "RF"; + names += "IF"; + names += "BB"; + + return names; } osmosdr::gain_range_t hackrf_source_c::get_gain_range( size_t chan ) @@ -331,17 +595,34 @@ osmosdr::gain_range_t hackrf_source_c::get_gain_range( const std::string & name, bool hackrf_source_c::set_gain_mode( bool automatic, size_t chan ) { - return hackrf_common::set_gain_mode(automatic, chan); + _auto_gain = automatic; + + return get_gain_mode(chan); } bool hackrf_source_c::get_gain_mode( size_t chan ) { - return hackrf_common::get_gain_mode(chan); + return _auto_gain; } double hackrf_source_c::set_gain( double gain, size_t chan ) { - return hackrf_common::set_gain(gain, chan); + int ret; + osmosdr::gain_range_t rf_gains = get_gain_range( "RF", chan ); + + if (_dev) { + double clip_gain = rf_gains.clip( gain, true ); + uint8_t value = clip_gain == 14.0f ? 1 : 0; + + ret = hackrf_set_amp_enable( _dev, value ); + if ( HACKRF_SUCCESS == ret ) { + _amp_gain = clip_gain; + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_amp_enable", value ) ) + } + } + + return _amp_gain; } double hackrf_source_c::set_gain( double gain, const std::string & name, size_t chan) @@ -363,7 +644,7 @@ double hackrf_source_c::set_gain( double gain, const std::string & name, size_t double hackrf_source_c::get_gain( size_t chan ) { - return hackrf_common::get_gain(chan); + return _amp_gain; } double hackrf_source_c::get_gain( const std::string & name, size_t chan ) @@ -388,10 +669,10 @@ double hackrf_source_c::set_if_gain(double gain, size_t chan) int ret; osmosdr::gain_range_t rf_gains = get_gain_range( "IF", chan ); - if (_dev.get()) { + if (_dev) { double clip_gain = rf_gains.clip( gain, true ); - ret = hackrf_set_lna_gain( _dev.get(), uint32_t(clip_gain) ); + ret = hackrf_set_lna_gain( _dev, uint32_t(clip_gain) ); if ( HACKRF_SUCCESS == ret ) { _lna_gain = clip_gain; } else { @@ -407,10 +688,10 @@ double hackrf_source_c::set_bb_gain( double gain, size_t chan ) int ret; osmosdr::gain_range_t if_gains = get_gain_range( "BB", chan ); - if (_dev.get()) { + if (_dev) { double clip_gain = if_gains.clip( gain, true ); - ret = hackrf_set_vga_gain( _dev.get(), uint32_t(clip_gain) ); + ret = hackrf_set_vga_gain( _dev, uint32_t(clip_gain) ); if ( HACKRF_SUCCESS == ret ) { _vga_gain = clip_gain; } else { @@ -423,30 +704,72 @@ double hackrf_source_c::set_bb_gain( double gain, size_t chan ) std::vector< std::string > hackrf_source_c::get_antennas( size_t chan ) { - return hackrf_common::get_antennas(chan); + std::vector< std::string > antennas; + + antennas += get_antenna( chan ); + + return antennas; } std::string hackrf_source_c::set_antenna( const std::string & antenna, size_t chan ) { - return hackrf_common::set_antenna(antenna, chan); + return get_antenna( chan ); } std::string hackrf_source_c::get_antenna( size_t chan ) { - return hackrf_common::get_antenna(chan); + return "TX/RX"; } double hackrf_source_c::set_bandwidth( double bandwidth, size_t chan ) { - return hackrf_common::set_bandwidth(bandwidth, chan); + int ret; +// osmosdr::freq_range_t bandwidths = get_bandwidth_range( chan ); + + if ( bandwidth == 0.0 ) /* bandwidth of 0 means automatic filter selection */ + bandwidth = _sample_rate * 0.75; /* select narrower filters to prevent aliasing */ + + if ( _dev ) { + /* compute best default value depending on sample rate (auto filter) */ + uint32_t bw = hackrf_compute_baseband_filter_bw( uint32_t(bandwidth) ); + ret = hackrf_set_baseband_filter_bandwidth( _dev, bw ); + if ( HACKRF_SUCCESS == ret ) { + _bandwidth = bw; + } else { + HACKRF_THROW_ON_ERROR( ret, HACKRF_FUNC_STR( "hackrf_set_baseband_filter_bandwidth", bw ) ) + } + } + + return _bandwidth; } double hackrf_source_c::get_bandwidth( size_t chan ) { - return hackrf_common::get_bandwidth(chan); + return _bandwidth; } osmosdr::freq_range_t hackrf_source_c::get_bandwidth_range( size_t chan ) { - return hackrf_common::get_bandwidth_range(chan); + osmosdr::freq_range_t bandwidths; + + // TODO: read out from libhackrf when an API is available + + bandwidths += osmosdr::range_t( 1750000 ); + bandwidths += osmosdr::range_t( 2500000 ); + bandwidths += osmosdr::range_t( 3500000 ); + bandwidths += osmosdr::range_t( 5000000 ); + bandwidths += osmosdr::range_t( 5500000 ); + bandwidths += osmosdr::range_t( 6000000 ); + bandwidths += osmosdr::range_t( 7000000 ); + bandwidths += osmosdr::range_t( 8000000 ); + bandwidths += osmosdr::range_t( 9000000 ); + bandwidths += osmosdr::range_t( 10000000 ); + bandwidths += osmosdr::range_t( 12000000 ); + bandwidths += osmosdr::range_t( 14000000 ); + bandwidths += osmosdr::range_t( 15000000 ); + bandwidths += osmosdr::range_t( 20000000 ); + bandwidths += osmosdr::range_t( 24000000 ); + bandwidths += osmosdr::range_t( 28000000 ); + + return bandwidths; } diff --git a/lib/hackrf/hackrf_source_c.h b/lib/hackrf/hackrf_source_c.h index 0d38ac0..6ae81d2 100644 --- a/lib/hackrf/hackrf_source_c.h +++ b/lib/hackrf/hackrf_source_c.h @@ -1,35 +1,36 @@ /* -*- c++ -*- */ /* * Copyright 2013 Dimitri Stolnikov <horiz0n@gmx.net> - * Copyright 2020 Clayton Smith <argilo@gmail.com> * - * gr-osmosdr is free software; you can redistribute it and/or modify + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) * any later version. * - * gr-osmosdr is distributed in the hope that it will be useful, + * GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to + * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef INCLUDED_HACKRF_SOURCE_C_H #define INCLUDED_HACKRF_SOURCE_C_H +#include <gnuradio/thread/thread.h> #include <gnuradio/sync_block.h> -#include <condition_variable> -#include <mutex> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include <libhackrf/hackrf.h> #include "source_iface.h" -#include "hackrf_common.h" class hackrf_source_c; @@ -61,12 +62,12 @@ hackrf_source_c_sptr make_hackrf_source_c (const std::string & args = ""); */ class hackrf_source_c : public gr::sync_block, - public source_iface, - protected hackrf_common + public source_iface { private: // The friend declaration allows make_hackrf_source_c to // access the private constructor. + friend hackrf_source_c_sptr make_hackrf_source_c (const std::string & args); /*! @@ -122,22 +123,35 @@ public: private: static int _hackrf_rx_callback(hackrf_transfer* transfer); int hackrf_rx_callback(unsigned char *buf, uint32_t len); + static void _hackrf_wait(hackrf_source_c *obj); + void hackrf_wait(); + + static int _usage; + static boost::mutex _usage_mutex; - std::vector<float> _lut; + std::vector<gr_complex> _lut; - unsigned char **_buf; + hackrf_device *_dev; + gr::thread::thread _thread; + unsigned short **_buf; unsigned int _buf_num; unsigned int _buf_len; unsigned int _buf_head; unsigned int _buf_used; - std::mutex _buf_mutex; - std::condition_variable _buf_cond; + boost::mutex _buf_mutex; + boost::condition_variable _buf_cond; unsigned int _buf_offset; int _samp_avail; + double _sample_rate; + double _center_freq; + double _freq_corr; + bool _auto_gain; + double _amp_gain; double _lna_gain; double _vga_gain; + double _bandwidth; }; #endif /* INCLUDED_HACKRF_SOURCE_C_H */ diff --git a/lib/xtrx/CMakeLists.txt b/lib/miri/CMakeLists.txt index 9297bf0..ddaeb0a 100644 --- a/lib/xtrx/CMakeLists.txt +++ b/lib/miri/CMakeLists.txt @@ -21,15 +21,17 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} - ${LIBXTRX_INCLUDE_DIRS} + ${LIBMIRISDR_INCLUDE_DIRS} ) -list(APPEND gr_osmosdr_srcs - ${CMAKE_CURRENT_SOURCE_DIR}/xtrx_obj.cc - ${CMAKE_CURRENT_SOURCE_DIR}/xtrx_source_c.cc - ${CMAKE_CURRENT_SOURCE_DIR}/xtrx_sink_c.cc +set(mirisdr_srcs + ${CMAKE_CURRENT_SOURCE_DIR}/miri_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) +######################################################################## +# Append gnuradio-mirisdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${mirisdr_srcs}) +list(APPEND gr_osmosdr_libs ${LIBMIRISDR_LIBRARIES}) diff --git a/lib/miri/miri_source_c.cc b/lib/miri/miri_source_c.cc new file mode 100644 index 0000000..c9f81fa --- /dev/null +++ b/lib/miri/miri_source_c.cc @@ -0,0 +1,451 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> + * Copyright 2012 Steve Markgraf <steve@steve-m.de> + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * config.h is generated by configure. It contains the results + * of probing for features, options etc. It should be the first + * file included in your .cc file. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "miri_source_c.h" +#include <gnuradio/io_signature.h> + +#include <boost/assign.hpp> +#include <boost/format.hpp> + +#include <stdexcept> +#include <iostream> +#include <stdio.h> + +#include <mirisdr.h> + +#include "arg_helpers.h" + +using namespace boost::assign; + +#define BUF_SIZE 2304 * 8 * 2 +#define BUF_NUM 15 +#define BUF_SKIP 1 // buffers to skip due to garbage + +#define BYTES_PER_SAMPLE 4 // mirisdr device delivers 16 bit signed IQ data + // containing 12 bits of information + +/* + * Create a new instance of miri_source_c and return + * a boost shared_ptr. This is effectively the public constructor. + */ +miri_source_c_sptr +make_miri_source_c (const std::string &args) +{ + return gnuradio::get_initial_sptr(new miri_source_c (args)); +} + +/* + * Specify constraints on number of input and output streams. + * This info is used to construct the input and output signatures + * (2nd & 3rd args to gr::block's constructor). The input and + * output signatures are used by the runtime system to + * check that a valid number and type of inputs and outputs + * are connected to this block. In this case, we accept + * only 0 input and 1 output. + */ +static const int MIN_IN = 0; // mininum number of input streams +static const int MAX_IN = 0; // maximum number of input streams +static const int MIN_OUT = 1; // minimum number of output streams +static const int MAX_OUT = 1; // maximum number of output streams + +/* + * The private constructor + */ +miri_source_c::miri_source_c (const std::string &args) + : gr::sync_block ("miri_source_c", + gr::io_signature::make(MIN_IN, MAX_IN, sizeof (gr_complex)), + gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (gr_complex))), + _running(true), + _auto_gain(false), + _skipped(0) +{ + int ret; + unsigned int dev_index = 0; + + dict_t dict = params_to_dict(args); + + if (dict.count("miri")) + dev_index = boost::lexical_cast< unsigned int >( dict["miri"] ); + + _buf_num = _buf_head = _buf_used = _buf_offset = 0; + _samp_avail = BUF_SIZE / BYTES_PER_SAMPLE; + + if (dict.count("buffers")) + _buf_num = boost::lexical_cast< unsigned int >( dict["buffers"] ); + + if (0 == _buf_num) + _buf_num = BUF_NUM; + + if ( BUF_NUM != _buf_num ) { + std::cerr << "Using " << _buf_num << " buffers of size " << BUF_SIZE << "." + << std::endl; + } + + if ( dev_index >= mirisdr_get_device_count() ) + throw std::runtime_error("Wrong mirisdr device index given."); + + std::cerr << "Using device #" << dev_index << ": " + << mirisdr_get_device_name(dev_index) + << std::endl; + + _dev = NULL; + ret = mirisdr_open( &_dev, dev_index ); + if (ret < 0) + throw std::runtime_error("Failed to open mirisdr device."); +#if 0 + ret = mirisdr_set_sample_rate( _dev, 500000 ); + if (ret < 0) + throw std::runtime_error("Failed to set default samplerate."); + + ret = mirisdr_set_tuner_gain_mode(_dev, int(!_auto_gain)); + if (ret < 0) + throw std::runtime_error("Failed to enable manual gain mode."); +#endif + ret = mirisdr_reset_buffer( _dev ); + if (ret < 0) + throw std::runtime_error("Failed to reset usb buffers."); + + _buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *)); + _buf_lens = (unsigned int *) malloc(_buf_num * sizeof(unsigned int)); + + if (_buf && _buf_lens) { + for(unsigned int i = 0; i < _buf_num; ++i) + _buf[i] = (unsigned short *) malloc(BUF_SIZE); + } + + _thread = gr::thread::thread(_mirisdr_wait, this); +} + +/* + * Our virtual destructor. + */ +miri_source_c::~miri_source_c () +{ + if (_dev) { + _running = false; + mirisdr_cancel_async( _dev ); + _thread.join(); + mirisdr_close( _dev ); + _dev = NULL; + } + + if (_buf) { + for(unsigned int i = 0; i < _buf_num; ++i) { + free(_buf[i]); + } + + free(_buf); + _buf = NULL; + free(_buf_lens); + _buf_lens = NULL; + } +} + +void miri_source_c::_mirisdr_callback(unsigned char *buf, uint32_t len, void *ctx) +{ + miri_source_c *obj = (miri_source_c *)ctx; + obj->mirisdr_callback(buf, len); +} + +void miri_source_c::mirisdr_callback(unsigned char *buf, uint32_t len) +{ + if (_skipped < BUF_SKIP) { + _skipped++; + return; + } + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + if (len > BUF_SIZE) + throw std::runtime_error("Buffer too small."); + + int buf_tail = (_buf_head + _buf_used) % _buf_num; + memcpy(_buf[buf_tail], buf, len); + _buf_lens[buf_tail] = len; + + if (_buf_used == _buf_num) { + std::cerr << "O" << std::flush; + _buf_head = (_buf_head + 1) % _buf_num; + } else { + _buf_used++; + } + } + + _buf_cond.notify_one(); +} + +void miri_source_c::_mirisdr_wait(miri_source_c *obj) +{ + obj->mirisdr_wait(); +} + +void miri_source_c::mirisdr_wait() +{ + int ret = mirisdr_read_async( _dev, _mirisdr_callback, (void *)this, _buf_num, BUF_SIZE ); + + _running = false; + + if ( ret != 0 ) + std::cerr << "mirisdr_read_async returned with " << ret << std::endl; + + _buf_cond.notify_one(); +} + +int miri_source_c::work( int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items ) +{ + gr_complex *out = (gr_complex *)output_items[0]; + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + while (_buf_used < 3 && _running) // collect at least 3 buffers + _buf_cond.wait( lock ); + } + + if (!_running) + return WORK_DONE; + + short *buf = (short *)_buf[_buf_head] + _buf_offset; + + if (noutput_items <= _samp_avail) { + for (int i = 0; i < noutput_items; i++) + *out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/4096.0f), + float(*(buf + i * 2 + 1)) * (1.0f/4096.0f) ); + + _buf_offset += noutput_items * 2; + _samp_avail -= noutput_items; + } else { + for (int i = 0; i < _samp_avail; i++) + *out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/4096.0f), + float(*(buf + i * 2 + 1)) * (1.0f/4096.0f) ); + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + _buf_head = (_buf_head + 1) % _buf_num; + _buf_used--; + } + + buf = (short *)_buf[_buf_head]; + + int remaining = noutput_items - _samp_avail; + + for (int i = 0; i < remaining; i++) + *out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/4096.0f), + float(*(buf + i * 2 + 1)) * (1.0f/4096.0f) ); + + _buf_offset = remaining * 2; + _samp_avail = (_buf_lens[_buf_head] / BYTES_PER_SAMPLE) - remaining; + } + + return noutput_items; +} + +std::vector<std::string> miri_source_c::get_devices() +{ + std::vector<std::string> devices; + + for (unsigned int i = 0; i < mirisdr_get_device_count(); i++) { + std::string args = "miri=" + boost::lexical_cast< std::string >( i ); + args += ",label='" + std::string(mirisdr_get_device_name( i )) + "'"; + devices.push_back( args ); + } + + return devices; +} + +size_t miri_source_c::get_num_channels() +{ + return 1; +} + +osmosdr::meta_range_t miri_source_c::get_sample_rates() +{ + osmosdr::meta_range_t range; + + range += osmosdr::range_t( 8000000 ); // known to work + + return range; +} + +double miri_source_c::set_sample_rate(double rate) +{ + if (_dev) { + mirisdr_set_sample_rate( _dev, (uint32_t)rate ); + } + + return get_sample_rate(); +} + +double miri_source_c::get_sample_rate() +{ + if (_dev) + return (double)mirisdr_get_sample_rate( _dev ); + + return 0; +} + +osmosdr::freq_range_t miri_source_c::get_freq_range( size_t chan ) +{ + osmosdr::freq_range_t range; + + range += osmosdr::range_t( 150e3, 30e6 ); /* LW/MW/SW (150 kHz - 30 MHz) */ + range += osmosdr::range_t( 64e6, 108e6 ); /* VHF Band II (64 - 108 MHz) */ + range += osmosdr::range_t( 162e6, 240e6 ); /* Band III (162 - 240 MHz) */ + range += osmosdr::range_t( 470e6, 960e6 ); /* Band IV/V (470 - 960 MHz) */ + range += osmosdr::range_t( 1450e6, 1675e6 ); /* L-Band (1450 - 1675 MHz) */ + + return range; +} + +double miri_source_c::set_center_freq( double freq, size_t chan ) +{ + if (_dev) + mirisdr_set_center_freq( _dev, (uint32_t)freq ); + + return get_center_freq( chan ); +} + +double miri_source_c::get_center_freq( size_t chan ) +{ + if (_dev) + return (double)mirisdr_get_center_freq( _dev ); + + return 0; +} + +double miri_source_c::set_freq_corr( double ppm, size_t chan ) +{ + return get_freq_corr( chan ); +} + +double miri_source_c::get_freq_corr( size_t chan ) +{ + return 0; +} + +std::vector<std::string> miri_source_c::get_gain_names( size_t chan ) +{ + std::vector< std::string > gains; + + gains += "LNA"; + + return gains; +} + +osmosdr::gain_range_t miri_source_c::get_gain_range( size_t chan ) +{ + osmosdr::gain_range_t range; + + if (_dev) { + int count = mirisdr_get_tuner_gains(_dev, NULL); + if (count > 0) { + int* gains = new int[ count ]; + count = mirisdr_get_tuner_gains(_dev, gains); + for (int i = 0; i < count; i++) + range += osmosdr::range_t( gains[i] / 10.0 ); + delete[] gains; + } + } + + return range; +} + +osmosdr::gain_range_t miri_source_c::get_gain_range( const std::string & name, size_t chan ) +{ + return get_gain_range( chan ); +} + +bool miri_source_c::set_gain_mode( bool automatic, size_t chan ) +{ + if (_dev) { + if (!mirisdr_set_tuner_gain_mode(_dev, int(!automatic))) { + _auto_gain = automatic; + } + } + + return get_gain_mode(chan); +} + +bool miri_source_c::get_gain_mode( size_t chan ) +{ + return _auto_gain; +} + +double miri_source_c::set_gain( double gain, size_t chan ) +{ + osmosdr::gain_range_t rf_gains = miri_source_c::get_gain_range( chan ); + + if (_dev) { + mirisdr_set_tuner_gain( _dev, int(rf_gains.clip(gain) * 10.0) ); + } + + return get_gain( chan ); +} + +double miri_source_c::set_gain( double gain, const std::string & name, size_t chan) +{ + return set_gain( gain, chan ); +} + +double miri_source_c::get_gain( size_t chan ) +{ + if ( _dev ) + return ((double)mirisdr_get_tuner_gain( _dev )) / 10.0; + + return 0; +} + +double miri_source_c::get_gain( const std::string & name, size_t chan ) +{ + return get_gain( chan ); +} + +std::vector< std::string > miri_source_c::get_antennas( size_t chan ) +{ + std::vector< std::string > antennas; + + antennas += get_antenna( chan ); + + return antennas; +} + +std::string miri_source_c::set_antenna( const std::string & antenna, size_t chan ) +{ + return get_antenna( chan ); +} + +std::string miri_source_c::get_antenna( size_t chan ) +{ + return "RX"; +} diff --git a/lib/airspyhf/airspyhf_source_c.h b/lib/miri/miri_source_c.h index dbdd87a..5363db5 100644 --- a/lib/airspyhf/airspyhf_source_c.h +++ b/lib/miri/miri_source_c.h @@ -1,8 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2013 Dimitri Stolnikov <horiz0n@gmx.net> - * - * This file is part of GNU Radio + * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> * * GNU Radio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,54 +17,63 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_AIRSPYHF_SOURCE_C_H -#define INCLUDED_AIRSPYHF_SOURCE_C_H - -#include <boost/circular_buffer.hpp> - -#include <mutex> -#include <condition_variable> +#ifndef INCLUDED_MIRI_SOURCE_C_H +#define INCLUDED_MIRI_SOURCE_C_H #include <gnuradio/sync_block.h> -#include <libairspyhf/airspyhf.h> +#include <gnuradio/thread/thread.h> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include "source_iface.h" -class airspyhf_source_c; +class miri_source_c; +typedef struct mirisdr_dev mirisdr_dev_t; -typedef boost::shared_ptr<airspyhf_source_c> airspyhf_source_c_sptr; +/* + * We use boost::shared_ptr's instead of raw pointers for all access + * to gr::blocks (and many other data structures). The shared_ptr gets + * us transparent reference counting, which greatly simplifies storage + * management issues. This is especially helpful in our hybrid + * C++ / Python system. + * + * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm + * + * As a convention, the _sptr suffix indicates a boost::shared_ptr + */ +typedef boost::shared_ptr<miri_source_c> miri_source_c_sptr; /*! - * \brief Return a shared_ptr to a new instance of airspyhf_source_c. + * \brief Return a shared_ptr to a new instance of miri_source_c. * - * To avoid accidental use of raw pointers, airspyhf_source_c's - * constructor is private. make_airspyhf_source_c is the public + * To avoid accidental use of raw pointers, miri_source_c's + * constructor is private. make_miri_source_c is the public * interface for creating new instances. */ -airspyhf_source_c_sptr make_airspyhf_source_c (const std::string & args = ""); +miri_source_c_sptr make_miri_source_c (const std::string & args = ""); /*! * \brief Provides a stream of complex samples. * \ingroup block */ -class airspyhf_source_c : +class miri_source_c : public gr::sync_block, public source_iface { private: - // The friend declaration allows make_airspyhf_source_c to + // The friend declaration allows make_miri_source_c to // access the private constructor. - friend airspyhf_source_c_sptr make_airspyhf_source_c (const std::string & args); - - airspyhf_source_c (const std::string & args); + friend miri_source_c_sptr make_miri_source_c (const std::string & args); -public: - ~airspyhf_source_c (); + /*! + * \brief Provides a stream of complex samples. + */ + miri_source_c (const std::string & args); // private constructor - bool start(); - bool stop(); + public: + ~miri_source_c (); // public destructor int work( int noutput_items, gr_vector_const_void_star &input_items, @@ -89,6 +96,8 @@ public: std::vector<std::string> get_gain_names( size_t chan = 0 ); osmosdr::gain_range_t get_gain_range( size_t chan = 0 ); osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 ); + bool set_gain_mode( bool automatic, size_t chan = 0 ); + bool get_gain_mode( size_t chan = 0 ); double set_gain( double gain, size_t chan = 0 ); double set_gain( double gain, const std::string & name, size_t chan = 0 ); double get_gain( size_t chan = 0 ); @@ -98,21 +107,28 @@ public: std::string set_antenna( const std::string & antenna, size_t chan = 0 ); std::string get_antenna( size_t chan = 0 ); - private: - static int _airspyhf_rx_callback(airspyhf_transfer_t* transfer); - int airspyhf_rx_callback(void *samples, int sample_count); - - airspyhf_device *_dev; - - boost::circular_buffer<gr_complex> *_fifo; - std::mutex _fifo_lock; - std::condition_variable _samp_avail; - - std::vector< std::pair<double, uint32_t> > _sample_rates; - double _sample_rate; - double _center_freq; - double _freq_corr; + static void _mirisdr_callback(unsigned char *buf, uint32_t len, void *ctx); + void mirisdr_callback(unsigned char *buf, uint32_t len); + static void _mirisdr_wait(miri_source_c *obj); + void mirisdr_wait(); + + mirisdr_dev_t *_dev; + gr::thread::thread _thread; + unsigned short **_buf; + unsigned int *_buf_lens; + unsigned int _buf_num; + unsigned int _buf_head; + unsigned int _buf_used; + boost::mutex _buf_mutex; + boost::condition_variable _buf_cond; + bool _running; + + unsigned int _buf_offset; + int _samp_avail; + + bool _auto_gain; + unsigned int _skipped; }; -#endif /* INCLUDED_AIRSPY_SOURCE_C_H */ +#endif /* INCLUDED_MIRI_SOURCE_C_H */ diff --git a/lib/airspyhf/CMakeLists.txt b/lib/osmosdr/CMakeLists.txt index fc13ce2..b0872f8 100644 --- a/lib/airspyhf/CMakeLists.txt +++ b/lib/osmosdr/CMakeLists.txt @@ -1,19 +1,19 @@ -# Copyright 2017 Free Software Foundation, Inc. +# Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,17 +21,17 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} - ${LIBAIRSPYHF_INCLUDE_DIRS} + ${LIBOSMOSDR_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${Gnuradio-blocks_LIBRARIES} - ${LIBAIRSPYHF_LIBRARIES} +set(osmosdr_srcs + ${CMAKE_CURRENT_SOURCE_DIR}/osmosdr_src_c.cc ) -list(APPEND gr_osmosdr_srcs - ${CMAKE_CURRENT_SOURCE_DIR}/airspyhf_source_c.cc -) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${osmosdr_srcs}) +list(APPEND gr_osmosdr_libs ${LIBOSMOSDR_LIBRARIES}) diff --git a/lib/osmosdr/osmosdr_src_c.cc b/lib/osmosdr/osmosdr_src_c.cc new file mode 100644 index 0000000..de65373 --- /dev/null +++ b/lib/osmosdr/osmosdr_src_c.cc @@ -0,0 +1,533 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * config.h is generated by configure. It contains the results + * of probing for features, options etc. It should be the first + * file included in your .cc file. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "osmosdr_src_c.h" +#include <gnuradio/io_signature.h> + +#include <boost/assign.hpp> +#include <boost/format.hpp> + +#include <stdexcept> +#include <iostream> +#include <stdio.h> + +#include <osmosdr.h> + +#include "arg_helpers.h" + +using namespace boost::assign; + +#define BUF_LEN (16 * 32 * 512) /* must be multiple of 512 */ +#define BUF_NUM 15 +#define BUF_SKIP 1 // buffers to skip due to garbage + +#define BYTES_PER_SAMPLE 4 // osmosdr device delivers 16 bit signed IQ data + +/* + * Create a new instance of osmosdr_src_c and return + * a boost shared_ptr. This is effectively the public constructor. + */ +osmosdr_src_c_sptr +osmosdr_make_src_c (const std::string &args) +{ + return gnuradio::get_initial_sptr(new osmosdr_src_c (args)); +} + +/* + * The private constructor + */ +osmosdr_src_c::osmosdr_src_c (const std::string &args) + : gr::sync_block ("osmosdr_src_c", + gr::io_signature::make(0, 0, sizeof (gr_complex)), + gr::io_signature::make(1, 1, sizeof (gr_complex)) ), + _dev(NULL), + _buf(NULL), + _running(true), + _auto_gain(false), + _if_gain(0), + _skipped(0) +{ + int ret; + unsigned int dev_index = 0; + + dict_t dict = params_to_dict(args); + + if (dict.count("osmosdr")) + dev_index = boost::lexical_cast< unsigned int >( dict["osmosdr"] ); + + _buf_num = _buf_len = _buf_head = _buf_used = _buf_offset = 0; + + if (dict.count("buffers")) + _buf_num = boost::lexical_cast< unsigned int >( dict["buffers"] ); + + if (dict.count("buflen")) + _buf_len = boost::lexical_cast< unsigned int >( dict["buflen"] ); + + if (0 == _buf_num) + _buf_num = BUF_NUM; + + if (0 == _buf_len || _buf_len % 512 != 0) /* len must be multiple of 512 */ + _buf_len = BUF_LEN; + + if ( BUF_NUM != _buf_num || BUF_LEN != _buf_len ) { + std::cerr << "Using " << _buf_num << " buffers of size " << _buf_len << "." + << std::endl; + } + + _samp_avail = _buf_len / BYTES_PER_SAMPLE; + + if ( dev_index >= osmosdr_get_device_count() ) + throw std::runtime_error("Wrong osmosdr device index given."); + + std::cerr << "Using device #" << dev_index << ": " + << osmosdr_get_device_name(dev_index) + << std::endl; + + _dev = NULL; + ret = osmosdr_open( &_dev, dev_index ); + if (ret < 0) + throw std::runtime_error("Failed to open osmosdr device."); + + ret = osmosdr_set_fpga_iq_swap(_dev, 0); + if (ret < 0) + throw std::runtime_error("Failed to disable IQ swapping."); + + ret = osmosdr_set_sample_rate( _dev, 500000 ); + if (ret < 0) + throw std::runtime_error("Failed to set default samplerate."); + + ret = osmosdr_set_tuner_gain_mode(_dev, int(!_auto_gain)); + if (ret < 0) + throw std::runtime_error("Failed to enable manual gain mode."); + + ret = osmosdr_reset_buffer( _dev ); + if (ret < 0) + throw std::runtime_error("Failed to reset usb buffers."); + + set_if_gain( 24 ); /* preset to a reasonable default (non-GRC use case) */ + + _buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *)); + + if (_buf) { + for(unsigned int i = 0; i < _buf_num; ++i) + _buf[i] = (unsigned short *) malloc(_buf_len); + } + + _thread = gr::thread::thread(_osmosdr_wait, this); +} + +/* + * Our virtual destructor. + */ +osmosdr_src_c::~osmosdr_src_c () +{ + if (_dev) { + _running = false; + osmosdr_cancel_async( _dev ); + _thread.join(); + osmosdr_close( _dev ); + _dev = NULL; + } + + if (_buf) { + for(unsigned int i = 0; i < _buf_num; ++i) { + free(_buf[i]); + } + + free(_buf); + _buf = NULL; + } +} + +void osmosdr_src_c::_osmosdr_callback(unsigned char *buf, uint32_t len, void *ctx) +{ + osmosdr_src_c *obj = (osmosdr_src_c *)ctx; + obj->osmosdr_callback(buf, len); +} + +void osmosdr_src_c::osmosdr_callback(unsigned char *buf, uint32_t len) +{ + if (_skipped < BUF_SKIP) { + _skipped++; + return; + } + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + int buf_tail = (_buf_head + _buf_used) % _buf_num; + memcpy(_buf[buf_tail], buf, len); + + if (_buf_used == _buf_num) { + std::cerr << "O" << std::flush; + _buf_head = (_buf_head + 1) % _buf_num; + } else { + _buf_used++; + } + } + + _buf_cond.notify_one(); +} + +void osmosdr_src_c::_osmosdr_wait(osmosdr_src_c *obj) +{ + obj->osmosdr_wait(); +} + +void osmosdr_src_c::osmosdr_wait() +{ + int ret = osmosdr_read_async( _dev, _osmosdr_callback, (void *)this, _buf_num, _buf_len ); + + _running = false; + + if ( ret != 0 ) + std::cerr << "osmosdr_read_async returned with " << ret << std::endl; + + _buf_cond.notify_one(); +} + +int osmosdr_src_c::work( int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items ) +{ + gr_complex *out = (gr_complex *)output_items[0]; + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + while (_buf_used < 3 && _running) // collect at least 3 buffers + _buf_cond.wait( lock ); + } + + if (!_running) + return WORK_DONE; + + short *buf = (short *)_buf[_buf_head] + _buf_offset; + + if (noutput_items <= _samp_avail) { + for (int i = 0; i < noutput_items; i++) + *out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/32767.5f), + float(*(buf + i * 2 + 1)) * (1.0f/32767.5f) ); + + _buf_offset += noutput_items * 2; + _samp_avail -= noutput_items; + } else { + for (int i = 0; i < _samp_avail; i++) + *out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/32767.5f), + float(*(buf + i * 2 + 1)) * (1.0f/32767.5f) ); + + { + boost::mutex::scoped_lock lock( _buf_mutex ); + + _buf_head = (_buf_head + 1) % _buf_num; + _buf_used--; + } + + buf = (short *)_buf[_buf_head]; + + int remaining = noutput_items - _samp_avail; + + for (int i = 0; i < remaining; i++) + *out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/32767.5f), + float(*(buf + i * 2 + 1)) * (1.0f/32767.5f) ); + + _buf_offset = remaining * 2; + _samp_avail = (_buf_len / BYTES_PER_SAMPLE) - remaining; + } + + return noutput_items; +} + +std::vector<std::string> osmosdr_src_c::get_devices() +{ + std::vector< std::string > devices; + char buffer[256]; + + for (unsigned int i = 0; i < osmosdr_get_device_count(); i++) { + std::string args = "osmosdr=" + boost::lexical_cast< std::string >( i ); + + std::string label = std::string(osmosdr_get_device_name( i )); + + memset(buffer, 0, sizeof(buffer)); + osmosdr_get_device_usb_strings( i, NULL, NULL, buffer ); + std::string serial = std::string(buffer); + + if (serial.length()) + label += " " + serial; + + args += ",label='" + label + + "'"; + + devices.push_back( args ); + } + + return devices; +} + +size_t osmosdr_src_c::get_num_channels() +{ + return 1; +} + +osmosdr::meta_range_t osmosdr_src_c::get_sample_rates() +{ + osmosdr::meta_range_t range; + + if (_dev) { + int count = osmosdr_get_sample_rates(_dev, NULL); + if (count > 0) { + uint32_t* rates = new uint32_t[ count ]; + count = osmosdr_get_sample_rates(_dev, rates); + for (int i = 0; i < count; i++) + range += osmosdr::range_t( rates[i] ); + delete[] rates; + } + } + + return range; +} + +double osmosdr_src_c::set_sample_rate(double rate) +{ + if (_dev) { + osmosdr_set_sample_rate( _dev, (uint32_t)rate ); + } + + return get_sample_rate(); +} + +double osmosdr_src_c::get_sample_rate() +{ + if (_dev) + return (double)osmosdr_get_sample_rate( _dev ); + + return 0; +} + +osmosdr::freq_range_t osmosdr_src_c::get_freq_range( size_t chan ) +{ + osmosdr::freq_range_t range; + + /* there is a (temperature dependent) gap between 1100 to 1250 MHz */ + range += osmosdr::range_t( 52e6, 2.2e9 ); + + return range; +} + +double osmosdr_src_c::set_center_freq( double freq, size_t chan ) +{ + if (_dev) + osmosdr_set_center_freq( _dev, (uint32_t)freq ); + + return get_center_freq( chan ); +} + +double osmosdr_src_c::get_center_freq( size_t chan ) +{ + if (_dev) + return (double)osmosdr_get_center_freq( _dev ); + + return 0; +} + +double osmosdr_src_c::set_freq_corr( double ppm, size_t chan ) +{ + return get_freq_corr( chan ); +} + +double osmosdr_src_c::get_freq_corr( size_t chan ) +{ + return 0; +} + +std::vector<std::string> osmosdr_src_c::get_gain_names( size_t chan ) +{ + std::vector< std::string > names; + + names += "LNA"; + names += "IF"; + + return names; +} + +osmosdr::gain_range_t osmosdr_src_c::get_gain_range( size_t chan ) +{ + osmosdr::gain_range_t range; + + if (_dev) { + int count = osmosdr_get_tuner_gains(_dev, NULL); + if (count > 0) { + int* gains = new int[ count ]; + count = osmosdr_get_tuner_gains(_dev, gains); + for (int i = 0; i < count; i++) + range += osmosdr::range_t( gains[i] / 10.0 ); + delete[] gains; + } + } + + return range; +} + +osmosdr::gain_range_t osmosdr_src_c::get_gain_range( const std::string & name, size_t chan ) +{ + if ( "IF" == name ) { + return osmosdr::gain_range_t(3, 56, 1); + } + + return get_gain_range( chan ); +} + +bool osmosdr_src_c::set_gain_mode( bool automatic, size_t chan ) +{ + if (_dev) { + if (!osmosdr_set_tuner_gain_mode(_dev, int(!automatic))) { + _auto_gain = automatic; + } + } + + return get_gain_mode(chan); +} + +bool osmosdr_src_c::get_gain_mode( size_t chan ) +{ + return _auto_gain; +} + +double osmosdr_src_c::set_gain( double gain, size_t chan ) +{ + osmosdr::gain_range_t rf_gains = osmosdr_src_c::get_gain_range( chan ); + + if (_dev) { + osmosdr_set_tuner_gain( _dev, int(rf_gains.clip(gain) * 10.0) ); + } + + return get_gain( chan ); +} + +double osmosdr_src_c::set_gain( double gain, const std::string & name, size_t chan) +{ + if ( "IF" == name ) { + return set_if_gain( gain, chan ); + } + + return set_gain( gain, chan ); +} + +double osmosdr_src_c::get_gain( size_t chan ) +{ + if ( _dev ) + return ((double)osmosdr_get_tuner_gain( _dev )) / 10.0; + + return 0; +} + +double osmosdr_src_c::get_gain( const std::string & name, size_t chan ) +{ + if ( "IF" == name ) { + return _if_gain; + } + + return get_gain( chan ); +} + +double osmosdr_src_c::set_if_gain(double gain, size_t chan) +{ + std::vector< osmosdr::gain_range_t > if_gains; + + if_gains += osmosdr::gain_range_t(-3, 6, 9); + if_gains += osmosdr::gain_range_t(0, 9, 3); + if_gains += osmosdr::gain_range_t(0, 9, 3); + if_gains += osmosdr::gain_range_t(0, 2, 1); + if_gains += osmosdr::gain_range_t(3, 15, 3); + if_gains += osmosdr::gain_range_t(3, 15, 3); + + std::map< int, double > gains; + + /* initialize with min gains */ + for (unsigned int i = 0; i < if_gains.size(); i++) { + gains[ i + 1 ] = if_gains[ i ].start(); + } + + for (int i = if_gains.size() - 1; i >= 0; i--) { + osmosdr::gain_range_t range = if_gains[ i ]; + + double error = gain; + + for( double g = range.start(); g <= range.stop(); g += range.step() ) { + + double sum = 0; + for (int j = 0; j < int(gains.size()); j++) { + if ( i == j ) + sum += g; + else + sum += gains[ j + 1 ]; + } + + double err = abs(gain - sum); + if (err < error) { + error = err; + gains[ i + 1 ] = g; + } + } + } +#if 0 + std::cerr << gain << " => "; double sum = 0; + for (unsigned int i = 0; i < gains.size(); i++) { + sum += gains[ i + 1 ]; + std::cerr << gains[ i + 1 ] << " "; + } + std::cerr << " = " << sum << std::endl; +#endif + if (_dev) { + for (unsigned int stage = 1; stage <= gains.size(); stage++) { + osmosdr_set_tuner_if_gain( _dev, stage, int(gains[ stage ] * 10.0)); + } + } + + _if_gain = gain; + return gain; +} + +std::vector< std::string > osmosdr_src_c::get_antennas( size_t chan ) +{ + std::vector< std::string > antennas; + + antennas += get_antenna( chan ); + + return antennas; +} + +std::string osmosdr_src_c::set_antenna( const std::string & antenna, size_t chan ) +{ + return get_antenna( chan ); +} + +std::string osmosdr_src_c::get_antenna( size_t chan ) +{ + return "RX"; +} diff --git a/lib/osmosdr/osmosdr_src_c.h b/lib/osmosdr/osmosdr_src_c.h new file mode 100644 index 0000000..0f62b09 --- /dev/null +++ b/lib/osmosdr/osmosdr_src_c.h @@ -0,0 +1,139 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net> + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_OSMOSDR_SRC_C_H +#define INCLUDED_OSMOSDR_SRC_C_H + +#include <gnuradio/sync_block.h> + +#include <gnuradio/thread/thread.h> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> + +#include "source_iface.h" + +class osmosdr_src_c; +typedef struct osmosdr_dev osmosdr_dev_t; + +/* + * We use boost::shared_ptr's instead of raw pointers for all access + * to gr::blocks (and many other data structures). The shared_ptr gets + * us transparent reference counting, which greatly simplifies storage + * management issues. This is especially helpful in our hybrid + * C++ / Python system. + * + * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm + * + * As a convention, the _sptr suffix indicates a boost::shared_ptr + */ +typedef boost::shared_ptr<osmosdr_src_c> osmosdr_src_c_sptr; + +/*! + * \brief Return a shared_ptr to a new instance of osmosdr_src_c. + * + * To avoid accidental use of raw pointers, osmosdr_src_c's + * constructor is private. osmosdr_make_src_c is the public + * interface for creating new instances. + */ +osmosdr_src_c_sptr osmosdr_make_src_c (const std::string & args = ""); + +/*! + * \brief Provides a stream of complex samples. + * \ingroup block + * + * \sa sink for a version that subclasses gr::hier_block2. + */ +class osmosdr_src_c : + public gr::sync_block, + public source_iface +{ +private: + // The friend declaration allows osmosdr_make_src_c to + // access the private constructor. + + friend osmosdr_src_c_sptr osmosdr_make_src_c (const std::string & args); + + /*! + * \brief Provides a stream of complex samples. + */ + osmosdr_src_c (const std::string & args); // private constructor + + public: + ~osmosdr_src_c (); // public destructor + + int work( int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items ); + + static std::vector< std::string > get_devices(); + + size_t get_num_channels( void ); + + osmosdr::meta_range_t get_sample_rates( void ); + double set_sample_rate( double rate ); + double get_sample_rate( void ); + + osmosdr::freq_range_t get_freq_range( size_t chan = 0 ); + double set_center_freq( double freq, size_t chan = 0 ); + double get_center_freq( size_t chan = 0 ); + double set_freq_corr( double ppm, size_t chan = 0 ); + double get_freq_corr( size_t chan = 0 ); + + std::vector<std::string> get_gain_names( size_t chan = 0 ); + osmosdr::gain_range_t get_gain_range( size_t chan = 0 ); + osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 ); + bool set_gain_mode( bool automatic, size_t chan = 0 ); + bool get_gain_mode( size_t chan = 0 ); + double set_gain( double gain, size_t chan = 0 ); + double set_gain( double gain, const std::string & name, size_t chan = 0 ); + double get_gain( size_t chan = 0 ); + double get_gain( const std::string & name, size_t chan = 0 ); + + double set_if_gain( double gain, size_t chan = 0 ); + + std::vector< std::string > get_antennas( size_t chan = 0 ); + std::string set_antenna( const std::string & antenna, size_t chan = 0 ); + std::string get_antenna( size_t chan = 0 ); + +private: + static void _osmosdr_callback(unsigned char *buf, uint32_t len, void *ctx); + void osmosdr_callback(unsigned char *buf, uint32_t len); + static void _osmosdr_wait(osmosdr_src_c *obj); + void osmosdr_wait(); + + osmosdr_dev_t *_dev; + gr::thread::thread _thread; + unsigned short **_buf; + unsigned int _buf_num; + unsigned int _buf_len; + unsigned int _buf_head; + unsigned int _buf_used; + boost::mutex _buf_mutex; + boost::condition_variable _buf_cond; + bool _running; + + unsigned int _buf_offset; + int _samp_avail; + + bool _auto_gain; + double _if_gain; + unsigned int _skipped; +}; + +#endif /* INCLUDED_OSMOSDR_SRC_C_H */ diff --git a/lib/ranges.cc b/lib/ranges.cc index 09c1dae..cdff969 100644 --- a/lib/ranges.cc +++ b/lib/ranges.cc @@ -18,6 +18,7 @@ #include <osmosdr/ranges.h> #include <stdexcept> #include <boost/math/special_functions/round.hpp> +#include <boost/foreach.hpp> #include <algorithm> #include <sstream> @@ -101,7 +102,7 @@ meta_range_t::meta_range_t( double meta_range_t::start(void) const{ check_meta_range_monotonic(*this); double min_start = this->front().start(); - for (const range_t &r : (*this)){ + BOOST_FOREACH(const range_t &r, (*this)){ min_start = std::min(min_start, r.start()); } return min_start; @@ -110,7 +111,7 @@ double meta_range_t::start(void) const{ double meta_range_t::stop(void) const{ check_meta_range_monotonic(*this); double max_stop = this->front().stop(); - for (const range_t &r : (*this)){ + BOOST_FOREACH(const range_t &r, (*this)){ max_stop = std::max(max_stop, r.stop()); } return max_stop; @@ -120,7 +121,7 @@ double meta_range_t::step(void) const{ check_meta_range_monotonic(*this); std::vector<double> non_zero_steps; range_t last = this->front(); - for (const range_t &r : (*this)){ + BOOST_FOREACH(const range_t &r, (*this)){ //steps at each range if (r.step() > 0) non_zero_steps.push_back(r.step()); //and steps in-between ranges @@ -136,7 +137,7 @@ double meta_range_t::step(void) const{ double meta_range_t::clip(double value, bool clip_step) const{ check_meta_range_monotonic(*this); double last_stop = this->front().stop(); - for (const range_t &r : (*this)){ + BOOST_FOREACH(const range_t &r, (*this)){ //in-between ranges, clip to nearest if (value < r.start()){ return (std::abs(value - r.start()) < std::abs(value - last_stop))? @@ -156,7 +157,7 @@ double meta_range_t::clip(double value, bool clip_step) const{ std::vector<double> meta_range_t::values() const { std::vector<double> values; - for (const range_t &r : (*this)) { + BOOST_FOREACH(const range_t &r, (*this)) { if (r.start() != r.stop()) { if ( r.step() == 0 ) { values.push_back( r.start() ); @@ -176,7 +177,7 @@ std::vector<double> meta_range_t::values() const { const std::string meta_range_t::to_pp_string(void) const{ std::stringstream ss; - for (const range_t &r : (*this)){ + BOOST_FOREACH(const range_t &r, (*this)){ ss << r.to_pp_string() << std::endl; } return ss.str(); diff --git a/lib/redpitaya/CMakeLists.txt b/lib/redpitaya/CMakeLists.txt index 78f816b..a14dc9e 100644 --- a/lib/redpitaya/CMakeLists.txt +++ b/lib/redpitaya/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,17 +21,18 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -APPEND_LIB_LIST( - ${Gnuradio-blocks_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(redpitaya_srcs ${CMAKE_CURRENT_SOURCE_DIR}/redpitaya_source_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/redpitaya_sink_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/redpitaya_common.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${redpitaya_srcs}) +#list(APPEND gr_osmosdr_libs ${GNURADIO_BLOCKS_LIBRARIES}) diff --git a/lib/rfspace/CMakeLists.txt b/lib/rfspace/CMakeLists.txt index c096550..eebc15d 100644 --- a/lib/rfspace/CMakeLists.txt +++ b/lib/rfspace/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,11 +21,17 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -list(APPEND gr_osmosdr_srcs +set(rfspace_srcs ${CMAKE_CURRENT_SOURCE_DIR}/rfspace_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${rfspace_srcs}) +#list(APPEND gr_osmosdr_libs ...) + diff --git a/lib/rfspace/rfspace_source_c.cc b/lib/rfspace/rfspace_source_c.cc index 314dfc7..80f34df 100644 --- a/lib/rfspace/rfspace_source_c.cc +++ b/lib/rfspace/rfspace_source_c.cc @@ -27,6 +27,7 @@ #include "config.h" #endif +#ifndef USE_ASIO #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> @@ -34,6 +35,7 @@ #include <netinet/udp.h> #include <arpa/inet.h> #include <netdb.h> +#endif #include <fcntl.h> #include <unistd.h> @@ -52,6 +54,9 @@ #include <boost/format.hpp> #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> +#ifdef USE_ASIO +#include <boost/asio/deadline_timer.hpp> +#endif #include <gnuradio/io_signature.h> @@ -59,6 +64,9 @@ #include "rfspace_source_c.h" using namespace boost::assign; +#ifdef USE_ASIO +using boost::asio::deadline_timer; +#endif #define DEFAULT_HOST "127.0.0.1" /* We assume a running "siqs" from CuteSDR project */ #define DEFAULT_PORT 50000 @@ -94,8 +102,15 @@ rfspace_source_c::rfspace_source_c (const std::string &args) gr::io_signature::make (MIN_IN, MAX_IN, sizeof (gr_complex)), gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (gr_complex))), _radio(RADIO_UNKNOWN), +#ifdef USE_ASIO + _io_service(), + _resolver(_io_service), + _t(_io_service), + _u(_io_service), +#else _tcp(-1), _udp(-1), +#endif _usb(-1), _running(false), _keep_running(false), @@ -224,6 +239,30 @@ rfspace_source_c::rfspace_source_c (const std::string &args) /* SDR-IP 4.4.4 Data Output UDP IP and Port Address */ /* NETSDR 4.4.3 Data Output UDP IP and Port Address */ +#ifdef USE_ASIO + + tcp::resolver::query query(tcp::v4(), host.c_str(), port_str.c_str()); + tcp::resolver::iterator iterator = _resolver.resolve(query); + + boost::system::error_code ec; + + boost::asio::connect(_t, iterator, ec); + if ( ec ) + throw std::runtime_error(ec.message() + " (" + host + ":" + port_str + ")"); + + _u.open(udp::v4(), ec); + if ( ec ) + throw std::runtime_error(ec.message()); + + _u.bind(udp::endpoint(udp::v4(), DEFAULT_PORT), ec); + if ( ec ) + throw std::runtime_error(ec.message()); + + _u.set_option(udp::socket::reuse_address(true)); + _t.set_option(udp::socket::reuse_address(true)); + +#else + if ( (_tcp = socket(AF_INET, SOCK_STREAM, 0) ) < 0) { throw std::runtime_error("Could not create TCP socket"); @@ -300,6 +339,8 @@ rfspace_source_c::rfspace_source_c (const std::string &args) throw std::runtime_error("Bind of UDP socket failed: " + std::string(strerror(errno))); } +#endif + } /* Wait 10 ms before sending queries to device (required for networked radios). */ @@ -465,8 +506,10 @@ rfspace_source_c::rfspace_source_c (const std::string &args) */ rfspace_source_c::~rfspace_source_c () { +#ifndef USE_ASIO close(_tcp); close(_udp); +#endif if ( RFSPACE_SDR_IQ == _radio ) { @@ -547,7 +590,7 @@ bool rfspace_source_c::transaction( const unsigned char *cmd, size_t size, if ( write(_usb, cmd, size) != (int)size ) return false; - std::unique_lock<std::mutex> lock(_resp_lock); + boost::unique_lock<boost::mutex> lock(_resp_lock); _resp_avail.wait(lock); rx_bytes = _resp.size(); @@ -555,8 +598,13 @@ bool rfspace_source_c::transaction( const unsigned char *cmd, size_t size, } else { - std::lock_guard<std::mutex> lock(_tcp_lock); + boost::mutex::scoped_lock lock(_tcp_lock); + +#ifdef USE_ASIO + _t.write_some( boost::asio::buffer(cmd, size) ); + rx_bytes = _t.read_some( boost::asio::buffer(data, sizeof(data)) ); +#else if ( write(_tcp, cmd, size) != (int)size ) return false; @@ -576,6 +624,7 @@ bool rfspace_source_c::transaction( const unsigned char *cmd, size_t size, return false; rx_bytes = 2 + length; /* header + payload */ +#endif } response.resize( rx_bytes ); @@ -780,7 +829,7 @@ int rfspace_source_c::work( int noutput_items, { gr_complex *out = (gr_complex *)output_items[0]; - std::unique_lock<std::mutex> lock(_fifo_lock); + boost::unique_lock<boost::mutex> lock(_fifo_lock); /* Wait until we have the requested number of samples */ int n_samples_avail = _fifo->size(); @@ -803,6 +852,10 @@ int rfspace_source_c::work( int noutput_items, return noutput_items; } +#ifdef USE_ASIO + udp::endpoint ep; + size_t rx_bytes = _u.receive_from( boost::asio::buffer(data, sizeof(data)), ep ); +#else struct sockaddr_in sa_in; /* remote address */ socklen_t addrlen = sizeof(sa_in); /* length of addresses */ ssize_t rx_bytes = recvfrom(_udp, data, sizeof(data), 0, (struct sockaddr *)&sa_in, &addrlen); @@ -811,6 +864,7 @@ int rfspace_source_c::work( int noutput_items, std::cerr << "recvfrom returned " << rx_bytes << std::endl; return WORK_DONE; } +#endif #define HEADER_SIZE 2 #define SEQNUM_SIZE 2 @@ -838,7 +892,11 @@ int rfspace_source_c::work( int noutput_items, if ( diff > 1 ) { std::cerr << "Lost " << diff << " packets from " +#ifdef USE_ASIO + << ep +#else << inet_ntoa(sa_in.sin_addr) << ":" << ntohs(sa_in.sin_port) +#endif << std::endl; } @@ -919,11 +977,48 @@ typedef struct uint16_t port; } unit_t; +#ifdef USE_ASIO +static void handle_receive( const boost::system::error_code& ec, + std::size_t length, + boost::system::error_code* out_ec, + std::size_t* out_length ) +{ + *out_ec = ec; + *out_length = length; +} + +static void handle_timer( const boost::system::error_code& ec, + boost::system::error_code* out_ec ) +{ + *out_ec = boost::asio::error::timed_out; +} +#endif static std::vector < unit_t > discover_netsdr() { std::vector < unit_t > units; +#ifdef USE_ASIO + boost::system::error_code ec; + boost::asio::io_service ios; + udp::socket socket(ios); + deadline_timer timer(ios); + + timer.expires_at(boost::posix_time::pos_infin); + + socket.open(udp::v4(), ec); + + if ( ec ) + return units; + + socket.bind(udp::endpoint(udp::v4(), DISCOVER_CLIENT_PORT), ec); + + if ( ec ) + return units; + + socket.set_option(udp::socket::reuse_address(true)); + socket.set_option(boost::asio::socket_base::broadcast(true)); +#else int sock; if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) @@ -963,6 +1058,7 @@ static std::vector < unit_t > discover_netsdr() close(sock); return units; } +#endif discover_common_msg_t tx_msg; memset( (void *)&tx_msg, 0, sizeof(discover_common_msg_t) ); @@ -971,18 +1067,64 @@ static std::vector < unit_t > discover_netsdr() tx_msg.key[0] = KEY0; tx_msg.key[1] = KEY1; tx_msg.op = MSG_REQ; +#ifdef USE_ASIO + udp::endpoint ep(boost::asio::ip::address_v4::broadcast(), DISCOVER_SERVER_PORT); + socket.send_to(boost::asio::buffer(&tx_msg, sizeof(tx_msg)), ep); +#else sendto(sock, &tx_msg, sizeof(tx_msg), 0, (struct sockaddr *)&peer_sa, sizeof(peer_sa)); +#endif while ( true ) { std::size_t rx_bytes = 0; unsigned char data[1024*2]; +#ifdef USE_ASIO + // Set up the variables that receive the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + ec = boost::asio::error::would_block; + + // Start the asynchronous receive operation. The handle_receive function + // used as a callback will update the ec and rx_bytes variables. + socket.async_receive( boost::asio::buffer(data, sizeof(data)), + boost::bind(handle_receive, _1, _2, &ec, &rx_bytes) ); + + // Set a deadline for the asynchronous operation. + timer.expires_from_now( boost::posix_time::milliseconds(10) ); + + // Start an asynchronous wait on the timer. The handle_timer function + // used as a callback will update the ec variable. + timer.async_wait( boost::bind(handle_timer, _1, &ec) ); + + // Reset the io_service in preparation for a subsequent run_one() invocation. + ios.reset(); + + // Block until at least one asynchronous operation has completed. + do ios.run_one(); while ( ec == boost::asio::error::would_block ); + + if ( boost::asio::error::timed_out == ec ) /* timer was first to complete */ + { + // Please note that cancel() has portability issues on some versions of + // Microsoft Windows, and it may be necessary to use close() instead. + // Consult the documentation for cancel() for further information. + socket.cancel(); + + break; + } + else /* socket was first to complete */ + { + timer.cancel(); + } +#else socklen_t addrlen = sizeof(peer_sa); /* length of addresses */ int nbytes = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)&peer_sa, &addrlen); if ( nbytes <= 0 ) break; rx_bytes = nbytes; +#endif if ( rx_bytes >= sizeof(discover_common_msg_t) ) { @@ -1009,7 +1151,11 @@ static std::vector < unit_t > discover_netsdr() } } } +#ifdef USE_ASIO + socket.close(ec); +#else close(sock); +#endif return units; } @@ -1150,7 +1296,7 @@ std::vector<std::string> rfspace_source_c::get_devices( bool fake ) std::vector < unit_t > units = discover_netsdr(); - for (unit_t u : units) + BOOST_FOREACH( unit_t u, units ) { // std::cerr << u.name << " " << u.sn << " " << u.addr << ":" << u.port // << std::endl; @@ -1164,7 +1310,7 @@ std::vector<std::string> rfspace_source_c::get_devices( bool fake ) units = discover_sdr_iq(); - for (unit_t u : units) + BOOST_FOREACH( unit_t u, units ) { // std::cerr << u.name << " " << u.sn << " " << u.addr << ":" << u.port // << std::endl; diff --git a/lib/rfspace/rfspace_source_c.h b/lib/rfspace/rfspace_source_c.h index d2bf66d..c656063 100644 --- a/lib/rfspace/rfspace_source_c.h +++ b/lib/rfspace/rfspace_source_c.h @@ -20,17 +20,25 @@ #ifndef INCLUDED_RFSPACE_SOURCE_C_H #define INCLUDED_RFSPACE_SOURCE_C_H +//#define USE_ASIO + +#ifdef USE_ASIO +#include <boost/asio.hpp> +#endif #include <gnuradio/thread/thread.h> #include <gnuradio/block.h> #include <gnuradio/sync_block.h> #include <boost/circular_buffer.hpp> - -#include <mutex> -#include <condition_variable> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include "osmosdr/ranges.h" #include "source_iface.h" +#ifdef USE_ASIO +using boost::asio::ip::tcp; +using boost::asio::ip::udp; +#endif class rfspace_source_c; #ifndef SOCKET @@ -135,8 +143,15 @@ private: /* members */ radio_type _radio; +#ifdef USE_ASIO + boost::asio::io_service _io_service; + tcp::resolver _resolver; + tcp::socket _t; + udp::socket _u; +#else SOCKET _tcp; SOCKET _udp; +#endif int _usb; bool _running; bool _keep_running; @@ -149,15 +164,15 @@ private: /* members */ gr::thread::thread _thread; bool _run_usb_read_task; bool _run_tcp_keepalive_task; - std::mutex _tcp_lock; + boost::mutex _tcp_lock; boost::circular_buffer<gr_complex> *_fifo; - std::mutex _fifo_lock; - std::condition_variable _samp_avail; + boost::mutex _fifo_lock; + boost::condition_variable _samp_avail; std::vector< unsigned char > _resp; - std::mutex _resp_lock; - std::condition_variable _resp_avail; + boost::mutex _resp_lock; + boost::condition_variable _resp_avail; }; #endif /* INCLUDED_RFSPACE_SOURCE_C_H */ diff --git a/lib/rtl/CMakeLists.txt b/lib/rtl/CMakeLists.txt index 443f3c0..f438df5 100644 --- a/lib/rtl/CMakeLists.txt +++ b/lib/rtl/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,16 +21,18 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBRTLSDR_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${LIBRTLSDR_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(rtl_srcs ${CMAKE_CURRENT_SOURCE_DIR}/rtl_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${rtl_srcs}) +list(APPEND gr_osmosdr_libs ${LIBRTLSDR_LIBRARIES}) + diff --git a/lib/rtl/rtl_source_c.cc b/lib/rtl/rtl_source_c.cc index 5e3306b..a371464 100644 --- a/lib/rtl/rtl_source_c.cc +++ b/lib/rtl/rtl_source_c.cc @@ -32,6 +32,7 @@ #include <boost/assign.hpp> #include <boost/format.hpp> +#include <boost/detail/endian.hpp> #include <boost/algorithm/string.hpp> #include <stdexcept> @@ -297,7 +298,7 @@ void rtl_source_c::rtlsdr_callback(unsigned char *buf, uint32_t len) } { - std::lock_guard<std::mutex> lock( _buf_mutex ); + boost::mutex::scoped_lock lock( _buf_mutex ); int buf_tail = (_buf_head + _buf_used) % _buf_num; memcpy(_buf[buf_tail], buf, len); @@ -337,7 +338,7 @@ int rtl_source_c::work( int noutput_items, gr_complex *out = (gr_complex *)output_items[0]; { - std::unique_lock<std::mutex> lock( _buf_mutex ); + boost::mutex::scoped_lock lock( _buf_mutex ); while (_buf_used < 3 && _running) // collect at least 3 buffers _buf_cond.wait( lock ); @@ -358,7 +359,7 @@ int rtl_source_c::work( int noutput_items, if (!_samp_avail) { { - std::lock_guard<std::mutex> lock( _buf_mutex ); + boost::mutex::scoped_lock lock( _buf_mutex ); _buf_head = (_buf_head + 1) % _buf_num; _buf_used--; diff --git a/lib/rtl/rtl_source_c.h b/lib/rtl/rtl_source_c.h index de3e349..902b386 100644 --- a/lib/rtl/rtl_source_c.h +++ b/lib/rtl/rtl_source_c.h @@ -25,9 +25,8 @@ #include <gnuradio/sync_block.h> #include <gnuradio/thread/thread.h> - -#include <mutex> -#include <condition_variable> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include "source_iface.h" @@ -132,8 +131,8 @@ private: unsigned int _buf_len; unsigned int _buf_head; unsigned int _buf_used; - std::mutex _buf_mutex; - std::condition_variable _buf_cond; + boost::mutex _buf_mutex; + boost::condition_variable _buf_cond; bool _running; unsigned int _buf_offset; diff --git a/lib/rtl_tcp/CMakeLists.txt b/lib/rtl_tcp/CMakeLists.txt index 2de6cee..9f7c201 100644 --- a/lib/rtl_tcp/CMakeLists.txt +++ b/lib/rtl_tcp/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,15 +21,17 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -APPEND_LIB_LIST( - ${Gnuradio-blocks_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(rtl_tcp_srcs ${CMAKE_CURRENT_SOURCE_DIR}/rtl_tcp_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${rtl_tcp_srcs}) +#list(APPEND gr_osmosdr_libs ${GNURADIO_BLOCKS_LIBRARIES}) + diff --git a/lib/rtl_tcp/rtl_tcp_source_c.cc b/lib/rtl_tcp/rtl_tcp_source_c.cc index af8e300..ecdeee0 100644 --- a/lib/rtl_tcp/rtl_tcp_source_c.cc +++ b/lib/rtl_tcp/rtl_tcp_source_c.cc @@ -98,7 +98,7 @@ static int is_error( int perr ) case WSAENOPROTOOPT: return( perr == ENOPROTOOPT ); default: - fprintf(stderr,"rtl_tcp_source_c: unknown error %d WS err %d \n", perr, werr ); + fprintf(stderr,"rtl_tcp_source_f: unknown error %d WS err %d \n", perr, werr ); throw std::runtime_error("internal error"); } return 0; @@ -200,7 +200,7 @@ rtl_tcp_source_c::rtl_tcp_source_c(const std::string &args) : WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if( iResult != NO_ERROR ) { - report_error( "rtl_tcp_source_c WSAStartup", "can't open socket" ); + report_error( "rtl_tcp_source_f WSAStartup", "can't open socket" ); } #endif @@ -219,7 +219,7 @@ rtl_tcp_source_c::rtl_tcp_source_c(const std::string &args) : // FIXME leaks if report_error throws below int ret = getaddrinfo(host.c_str(), port_str, &hints, &ip_src); if (ret != 0) - report_error("rtl_tcp_source_c/getaddrinfo", + report_error("rtl_tcp_source_f/getaddrinfo", "can't initialize source socket" ); d_temp_buff = new unsigned char[payload_size]; // allow it to hold up to payload_size bytes @@ -261,8 +261,8 @@ rtl_tcp_source_c::rtl_tcp_source_c(const std::string &args) : report_error("SO_RCVTIMEO","can't set socket option SO_RCVTIMEO"); #endif // USE_RCV_TIMEO - if (::connect(d_socket, ip_src->ai_addr, ip_src->ai_addrlen) != 0) - report_error("rtl_tcp_source_c/connect","can't open TCP connection"); + while (::connect(d_socket, ip_src->ai_addr, ip_src->ai_addrlen) != 0) + ; // FIXME handle errors? freeaddrinfo(ip_src); int flag = 1; diff --git a/lib/sdrplay/CMakeLists.txt b/lib/sdrplay/CMakeLists.txt index 3d20a6f..382ab33 100644 --- a/lib/sdrplay/CMakeLists.txt +++ b/lib/sdrplay/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,16 +21,17 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBSDRPLAY_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${LIBSDRPLAY_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(sdrplay_srcs ${CMAKE_CURRENT_SOURCE_DIR}/sdrplay_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-sdrplay library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${sdrplay_srcs}) +list(APPEND gr_osmosdr_libs ${LIBSDRPLAY_LIBRARIES}) diff --git a/lib/sdrplay/sdrplay_source_c.h b/lib/sdrplay/sdrplay_source_c.h index b59f44a..2e4631e 100644 --- a/lib/sdrplay/sdrplay_source_c.h +++ b/lib/sdrplay/sdrplay_source_c.h @@ -24,9 +24,8 @@ #include <gnuradio/sync_block.h> #include <gnuradio/thread/thread.h> - -#include <mutex> -#include <condition_variable> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> #include "osmosdr/ranges.h" @@ -127,7 +126,7 @@ private: std::vector< short > _bufi; std::vector< short > _bufq; int _buf_offset; - std::mutex _buf_mutex; + boost::mutex _buf_mutex; bool _running; bool _uninit; diff --git a/lib/sink_impl.cc b/lib/sink_impl.cc index 317855a..d25e860 100644 --- a/lib/sink_impl.cc +++ b/lib/sink_impl.cc @@ -48,9 +48,6 @@ #ifdef ENABLE_FREESRP #include <freesrp_sink_c.h> #endif -#ifdef ENABLE_XTRX -#include "xtrx_sink_c.h" -#endif #ifdef ENABLE_FILE #include "file_sink_c.h" #endif @@ -102,9 +99,6 @@ sink_impl::sink_impl( const std::string &args ) #ifdef ENABLE_FREESRP dev_types.push_back("freesrp"); #endif -#ifdef ENABLE_XTRX - dev_types.push_back("xtrx"); -#endif #ifdef ENABLE_FILE dev_types.push_back("file"); #endif @@ -113,13 +107,13 @@ sink_impl::sink_impl( const std::string &args ) << GR_OSMOSDR_VERSION << " (" << GR_OSMOSDR_LIBVER << ") " << "gnuradio " << gr::version() << std::endl; std::cerr << "built-in sink types: "; - for (std::string dev_type : dev_types) + BOOST_FOREACH(std::string dev_type, dev_types) std::cerr << dev_type << " "; std::cerr << std::endl; - for (std::string arg : arg_list) { + BOOST_FOREACH(std::string arg, arg_list) { dict_t dict = params_to_dict(arg); - for (std::string dev_type : dev_types) { + BOOST_FOREACH(std::string dev_type, dev_types) { if ( dict.count( dev_type ) ) { device_specified = true; break; @@ -130,40 +124,36 @@ sink_impl::sink_impl( const std::string &args ) if ( ! device_specified ) { std::vector< std::string > dev_list; #ifdef ENABLE_UHD - for (std::string dev : uhd_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, uhd_sink_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_BLADERF - for (std::string dev : bladerf_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, bladerf_sink_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_HACKRF - for (std::string dev : hackrf_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, hackrf_sink_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_SOAPY - for (std::string dev : soapy_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, soapy_sink_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_REDPITAYA - for (std::string dev : redpitaya_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, redpitaya_sink_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_FREESRP - for (std::string dev : freesrp_sink_c::get_devices()) - dev_list.push_back( dev ); -#endif -#ifdef ENABLE_XTRX - for (std::string dev : xtrx_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, freesrp_sink_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_FILE - for (std::string dev : file_sink_c::get_devices()) + BOOST_FOREACH( std::string dev, file_sink_c::get_devices() ) dev_list.push_back( dev ); #endif // std::cerr << std::endl; -// for (std::string dev : dev_list) +// BOOST_FOREACH( std::string dev, dev_list ) // std::cerr << "'" << dev << "'" << std::endl; if ( dev_list.size() ) @@ -172,12 +162,12 @@ sink_impl::sink_impl( const std::string &args ) throw std::runtime_error("No supported devices found (check the connection and/or udev rules)."); } - for (std::string arg : arg_list) { + BOOST_FOREACH(std::string arg, arg_list) { dict_t dict = params_to_dict(arg); // std::cerr << std::endl; -// for (dict_t::value_type &entry : dict) +// BOOST_FOREACH( dict_t::value_type &entry, dict ) // std::cerr << "'" << entry.first << "' = '" << entry.second << "'" << std::endl; sink_iface *iface = NULL; @@ -219,12 +209,6 @@ sink_impl::sink_impl( const std::string &args ) block = sink; iface = sink.get(); } #endif -#ifdef ENABLE_XTRX - if ( dict.count("xtrx") ) { - xtrx_sink_c_sptr sink = make_xtrx_sink_c( arg ); - block = sink; iface = sink.get(); - } -#endif #ifdef ENABLE_FILE if ( dict.count("file") ) { file_sink_c_sptr sink = make_file_sink_c( arg ); @@ -245,13 +229,20 @@ sink_impl::sink_impl( const std::string &args ) if (!_devs.size()) throw std::runtime_error("No devices specified via device arguments."); + + /* Populate the _gain and _gain_mode arrays with the hardware state */ + BOOST_FOREACH( sink_iface *dev, _devs ) + for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { + _gain_mode[dev_chan] = dev->get_gain_mode(dev_chan); + _gain[dev_chan] = dev->get_gain(dev_chan); + } } size_t sink_impl::get_num_channels() { size_t channels = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) channels += dev->get_num_channels(); return channels; @@ -279,13 +270,13 @@ double sink_impl::set_sample_rate(double rate) if (_devs.empty()) throw std::runtime_error(NO_DEVICES_MSG); #endif - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) sample_rate = dev->set_sample_rate(rate); _sample_rate = sample_rate; } - return _sample_rate; + return sample_rate; } double sink_impl::get_sample_rate() @@ -304,7 +295,7 @@ double sink_impl::get_sample_rate() osmosdr::freq_range_t sink_impl::get_freq_range( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_freq_range( dev_chan ); @@ -315,7 +306,7 @@ osmosdr::freq_range_t sink_impl::get_freq_range( size_t chan ) double sink_impl::set_center_freq( double freq, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _center_freq[ chan ] != freq ) { @@ -330,7 +321,7 @@ double sink_impl::set_center_freq( double freq, size_t chan ) double sink_impl::get_center_freq( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_center_freq( dev_chan ); @@ -341,7 +332,7 @@ double sink_impl::get_center_freq( size_t chan ) double sink_impl::set_freq_corr( double ppm, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _freq_corr[ chan ] != ppm ) { @@ -356,7 +347,7 @@ double sink_impl::set_freq_corr( double ppm, size_t chan ) double sink_impl::get_freq_corr( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_freq_corr( dev_chan ); @@ -367,7 +358,7 @@ double sink_impl::get_freq_corr( size_t chan ) std::vector<std::string> sink_impl::get_gain_names( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_names( dev_chan ); @@ -378,7 +369,7 @@ std::vector<std::string> sink_impl::get_gain_names( size_t chan ) osmosdr::gain_range_t sink_impl::get_gain_range( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_range( dev_chan ); @@ -389,7 +380,7 @@ osmosdr::gain_range_t sink_impl::get_gain_range( size_t chan ) osmosdr::gain_range_t sink_impl::get_gain_range( const std::string & name, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_range( name, dev_chan ); @@ -400,7 +391,7 @@ osmosdr::gain_range_t sink_impl::get_gain_range( const std::string & name, size_ bool sink_impl::set_gain_mode( bool automatic, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _gain_mode[ chan ] != automatic ) { @@ -418,7 +409,7 @@ bool sink_impl::set_gain_mode( bool automatic, size_t chan ) bool sink_impl::get_gain_mode( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_mode( dev_chan ); @@ -429,7 +420,7 @@ bool sink_impl::get_gain_mode( size_t chan ) double sink_impl::set_gain( double gain, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _gain[ chan ] != gain ) { @@ -444,7 +435,7 @@ double sink_impl::set_gain( double gain, size_t chan ) double sink_impl::set_gain( double gain, const std::string & name, size_t chan) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->set_gain( gain, name, dev_chan ); @@ -455,7 +446,7 @@ double sink_impl::set_gain( double gain, const std::string & name, size_t chan) double sink_impl::get_gain( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain( dev_chan ); @@ -466,7 +457,7 @@ double sink_impl::get_gain( size_t chan ) double sink_impl::get_gain( const std::string & name, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain( name, dev_chan ); @@ -477,7 +468,7 @@ double sink_impl::get_gain( const std::string & name, size_t chan ) double sink_impl::set_if_gain( double gain, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _if_gain[ chan ] != gain ) { @@ -492,7 +483,7 @@ double sink_impl::set_if_gain( double gain, size_t chan ) double sink_impl::set_bb_gain( double gain, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _bb_gain[ chan ] != gain ) { @@ -507,7 +498,7 @@ double sink_impl::set_bb_gain( double gain, size_t chan ) std::vector< std::string > sink_impl::get_antennas( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_antennas( dev_chan ); @@ -518,7 +509,7 @@ std::vector< std::string > sink_impl::get_antennas( size_t chan ) std::string sink_impl::set_antenna( const std::string & antenna, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _antenna[ chan ] != antenna ) { @@ -533,7 +524,7 @@ std::string sink_impl::set_antenna( const std::string & antenna, size_t chan ) std::string sink_impl::get_antenna( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_antenna( dev_chan ); @@ -544,7 +535,7 @@ std::string sink_impl::get_antenna( size_t chan ) void sink_impl::set_dc_offset( const std::complex<double> &offset, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) dev->set_dc_offset( offset, dev_chan ); @@ -553,7 +544,7 @@ void sink_impl::set_dc_offset( const std::complex<double> &offset, size_t chan ) void sink_impl::set_iq_balance( const std::complex<double> &balance, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) dev->set_iq_balance( balance, dev_chan ); @@ -562,7 +553,7 @@ void sink_impl::set_iq_balance( const std::complex<double> &balance, size_t chan double sink_impl::set_bandwidth( double bandwidth, size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _bandwidth[ chan ] != bandwidth || 0.0f == bandwidth ) { @@ -577,7 +568,7 @@ double sink_impl::set_bandwidth( double bandwidth, size_t chan ) double sink_impl::get_bandwidth( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_bandwidth( dev_chan ); @@ -588,7 +579,7 @@ double sink_impl::get_bandwidth( size_t chan ) osmosdr::freq_range_t sink_impl::get_bandwidth_range( size_t chan ) { size_t channel = 0; - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_bandwidth_range( dev_chan ); @@ -681,7 +672,7 @@ void sink_impl::set_time_now(const osmosdr::time_spec_t &time_spec, size_t mboar void sink_impl::set_time_next_pps(const osmosdr::time_spec_t &time_spec) { - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) { dev->set_time_next_pps( time_spec ); } @@ -689,7 +680,7 @@ void sink_impl::set_time_next_pps(const osmosdr::time_spec_t &time_spec) void sink_impl::set_time_unknown_pps(const osmosdr::time_spec_t &time_spec) { - for (sink_iface *dev : _devs) + BOOST_FOREACH( sink_iface *dev, _devs ) { dev->set_time_unknown_pps( time_spec ); } diff --git a/lib/soapy/CMakeLists.txt b/lib/soapy/CMakeLists.txt index 7ac4d69..338bcaf 100644 --- a/lib/soapy/CMakeLists.txt +++ b/lib/soapy/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2015 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,18 +21,19 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${SoapySDR_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - ${SoapySDR_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(soapy_srcs ${CMAKE_CURRENT_SOURCE_DIR}/soapy_common.cc ${CMAKE_CURRENT_SOURCE_DIR}/soapy_source_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/soapy_sink_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${soapy_srcs}) +list(APPEND gr_osmosdr_libs ${SoapySDR_LIBRARIES}) diff --git a/lib/soapy/soapy_common.cc b/lib/soapy/soapy_common.cc index e241967..0e277e4 100644 --- a/lib/soapy/soapy_common.cc +++ b/lib/soapy/soapy_common.cc @@ -36,8 +36,8 @@ osmosdr::gain_range_t soapy_range_to_gain_range(const SoapySDR::Range &r) return osmosdr::gain_range_t(r.minimum(), r.maximum(), step); } -std::mutex &get_soapy_maker_mutex(void) +boost::mutex &get_soapy_maker_mutex(void) { - static std::mutex m; + static boost::mutex m; return m; } diff --git a/lib/soapy/soapy_common.h b/lib/soapy/soapy_common.h index 8adb0db..87e46a5 100644 --- a/lib/soapy/soapy_common.h +++ b/lib/soapy/soapy_common.h @@ -23,8 +23,7 @@ #include <osmosdr/ranges.h> #include <SoapySDR/Types.hpp> - -#include <mutex> +#include <boost/thread/mutex.hpp> /*! * Convert a soapy range to a gain range. @@ -36,6 +35,6 @@ osmosdr::gain_range_t soapy_range_to_gain_range(const SoapySDR::Range &r); * Global mutex to protect factory routines. * (optional under 0.5 release above) */ -std::mutex &get_soapy_maker_mutex(void); +boost::mutex &get_soapy_maker_mutex(void); #endif /* INCLUDED_SOAPY_COMMON_H */ diff --git a/lib/soapy/soapy_sink_c.cc b/lib/soapy/soapy_sink_c.cc index 4aafc47..b12b8da 100644 --- a/lib/soapy/soapy_sink_c.cc +++ b/lib/soapy/soapy_sink_c.cc @@ -63,7 +63,7 @@ soapy_sink_c::soapy_sink_c (const std::string &args) gr::io_signature::make (0, 0, 0)) { { - std::lock_guard<std::mutex> l(get_soapy_maker_mutex()); + boost::mutex::scoped_lock l(get_soapy_maker_mutex()); _device = SoapySDR::Device::make(params_to_dict(args)); } _nchan = std::max(1, args_to_io_signature(args)->max_streams()); @@ -75,7 +75,7 @@ soapy_sink_c::soapy_sink_c (const std::string &args) soapy_sink_c::~soapy_sink_c(void) { _device->closeStream(_stream); - std::lock_guard<std::mutex> l(get_soapy_maker_mutex()); + boost::mutex::scoped_lock l(get_soapy_maker_mutex()); SoapySDR::Device::unmake(_device); } @@ -107,7 +107,7 @@ std::vector<std::string> soapy_sink_c::get_devices() { std::vector<std::string> result; int i = 0; - for (SoapySDR::Kwargs kw : SoapySDR::Device::enumerate()) + BOOST_FOREACH(SoapySDR::Kwargs kw, SoapySDR::Device::enumerate()) { kw["soapy"] = boost::lexical_cast<std::string>(i++); result.push_back(dict_to_args_string(kw)); @@ -124,12 +124,12 @@ osmosdr::meta_range_t soapy_sink_c::get_sample_rates( void ) { osmosdr::meta_range_t result; #ifdef SOAPY_SDR_API_HAS_GET_SAMPLE_RATE_RANGE - for (const SoapySDR::Range &r : _device->getSampleRateRange(SOAPY_SDR_TX, 0)) + BOOST_FOREACH(const SoapySDR::Range &r, _device->getSampleRateRange(SOAPY_SDR_TX, 0)) { result.push_back(osmosdr::range_t(r.minimum(), r.maximum())); } #else - for (const double rate : _device->listSampleRates(SOAPY_SDR_TX, 0)) + BOOST_FOREACH(const double rate, _device->listSampleRates(SOAPY_SDR_TX, 0)) { result.push_back(osmosdr::range_t(rate)); } @@ -151,7 +151,7 @@ double soapy_sink_c::get_sample_rate( void ) osmosdr::freq_range_t soapy_sink_c::get_freq_range( size_t chan) { osmosdr::meta_range_t result; - for (const SoapySDR::Range r : _device->getFrequencyRange(SOAPY_SDR_TX, 0)) + BOOST_FOREACH(const SoapySDR::Range r, _device->getFrequencyRange(SOAPY_SDR_TX, 0)) { result.push_back(osmosdr::range_t(r.minimum(), r.maximum())); } @@ -309,12 +309,12 @@ osmosdr::freq_range_t soapy_sink_c::get_bandwidth_range( size_t chan) { osmosdr::meta_range_t result; #ifdef SOAPY_SDR_API_HAS_GET_BANDWIDTH_RANGE - for (const SoapySDR::Range &r : _device->getBandwidthRange(SOAPY_SDR_TX, 0)) + BOOST_FOREACH(const SoapySDR::Range &r, _device->getBandwidthRange(SOAPY_SDR_TX, 0)) { result.push_back(osmosdr::range_t(r.minimum(), r.maximum())); } #else - for (const double bw : _device->listBandwidths(SOAPY_SDR_TX, 0)) + BOOST_FOREACH(const double bw, _device->listBandwidths(SOAPY_SDR_TX, 0)) { result.push_back(osmosdr::range_t(bw)); } diff --git a/lib/soapy/soapy_source_c.cc b/lib/soapy/soapy_source_c.cc index 4dc9efc..a645361 100644 --- a/lib/soapy/soapy_source_c.cc +++ b/lib/soapy/soapy_source_c.cc @@ -64,7 +64,7 @@ soapy_source_c::soapy_source_c (const std::string &args) args_to_io_signature(args)) { { - std::lock_guard<std::mutex> l(get_soapy_maker_mutex()); + boost::mutex::scoped_lock l(get_soapy_maker_mutex()); _device = SoapySDR::Device::make(params_to_dict(args)); } _nchan = std::max(1, args_to_io_signature(args)->max_streams()); @@ -76,7 +76,7 @@ soapy_source_c::soapy_source_c (const std::string &args) soapy_source_c::~soapy_source_c(void) { _device->closeStream(_stream); - std::lock_guard<std::mutex> l(get_soapy_maker_mutex()); + boost::mutex::scoped_lock l(get_soapy_maker_mutex()); SoapySDR::Device::unmake(_device); } @@ -96,14 +96,9 @@ int soapy_source_c::work( int noutput_items, { int flags = 0; long long timeNs = 0; - int ret; - int retries = 1; - - do { - ret = _device->readStream( - _stream, &output_items[0], - noutput_items, flags, timeNs); - } while (retries-- && (ret == SOAPY_SDR_OVERFLOW)); + int ret = _device->readStream( + _stream, &output_items[0], + noutput_items, flags, timeNs); if (ret < 0) return 0; //call again return ret; @@ -113,7 +108,7 @@ std::vector<std::string> soapy_source_c::get_devices() { std::vector<std::string> result; int i = 0; - for (SoapySDR::Kwargs kw : SoapySDR::Device::enumerate()) + BOOST_FOREACH(SoapySDR::Kwargs kw, SoapySDR::Device::enumerate()) { kw["soapy"] = boost::lexical_cast<std::string>(i++); result.push_back(dict_to_args_string(kw)); @@ -130,12 +125,12 @@ osmosdr::meta_range_t soapy_source_c::get_sample_rates( void ) { osmosdr::meta_range_t result; #ifdef SOAPY_SDR_API_HAS_GET_SAMPLE_RATE_RANGE - for (const SoapySDR::Range &r : _device->getSampleRateRange(SOAPY_SDR_RX, 0)) + BOOST_FOREACH(const SoapySDR::Range &r, _device->getSampleRateRange(SOAPY_SDR_RX, 0)) { result.push_back(osmosdr::range_t(r.minimum(), r.maximum())); } #else - for (const double rate : _device->listSampleRates(SOAPY_SDR_RX, 0)) + BOOST_FOREACH(const double rate, _device->listSampleRates(SOAPY_SDR_RX, 0)) { result.push_back(osmosdr::range_t(rate)); } @@ -157,7 +152,7 @@ double soapy_source_c::get_sample_rate( void ) osmosdr::freq_range_t soapy_source_c::get_freq_range( size_t chan ) { osmosdr::meta_range_t result; - for (const SoapySDR::Range r : _device->getFrequencyRange(SOAPY_SDR_RX, 0)) + BOOST_FOREACH(const SoapySDR::Range r, _device->getFrequencyRange(SOAPY_SDR_RX, 0)) { result.push_back(osmosdr::range_t(r.minimum(), r.maximum())); } @@ -338,12 +333,12 @@ osmosdr::freq_range_t soapy_source_c::get_bandwidth_range( size_t chan ) { osmosdr::meta_range_t result; #ifdef SOAPY_SDR_API_HAS_GET_BANDWIDTH_RANGE - for (const SoapySDR::Range &r : _device->getBandwidthRange(SOAPY_SDR_RX, 0)) + BOOST_FOREACH(const SoapySDR::Range &r, _device->getBandwidthRange(SOAPY_SDR_RX, 0)) { result.push_back(osmosdr::range_t(r.minimum(), r.maximum())); } #else - for (const double bw : _device->listBandwidths(SOAPY_SDR_RX, 0)) + BOOST_FOREACH(const double bw, _device->listBandwidths(SOAPY_SDR_RX, 0)) { result.push_back(osmosdr::range_t(bw)); } diff --git a/lib/source_impl.cc b/lib/source_impl.cc index 8f2028b..f9a7e64 100644 --- a/lib/source_impl.cc +++ b/lib/source_impl.cc @@ -32,6 +32,10 @@ #include <gnuradio/blocks/throttle.h> #include <gnuradio/constants.h> +#ifdef ENABLE_OSMOSDR +#include <osmosdr_src_c.h> +#endif + #ifdef ENABLE_FCD #include <fcd_source_c.h> #endif @@ -52,6 +56,10 @@ #include <uhd_source_c.h> #endif +#ifdef ENABLE_MIRI +#include <miri_source_c.h> +#endif + #ifdef ENABLE_SDRPLAY #include <sdrplay_source_c.h> #endif @@ -72,10 +80,6 @@ #include <airspy_source_c.h> #endif -#ifdef ENABLE_AIRSPYHF -#include <airspyhf_source_c.h> -#endif - #ifdef ENABLE_SOAPY #include <soapy_source_c.h> #endif @@ -88,10 +92,6 @@ #include <freesrp_source_c.h> #endif -#ifdef ENABLE_XTRX -#include <xtrx_source_c.h> -#endif - #include "arg_helpers.h" #include "source_impl.h" @@ -124,6 +124,9 @@ source_impl::source_impl( const std::string &args ) #ifdef ENABLE_FILE dev_types.push_back("file"); #endif +#ifdef ENABLE_OSMOSDR + dev_types.push_back("osmosdr"); +#endif #ifdef ENABLE_FCD dev_types.push_back("fcd"); #endif @@ -136,6 +139,9 @@ source_impl::source_impl( const std::string &args ) #ifdef ENABLE_UHD dev_types.push_back("uhd"); #endif +#ifdef ENABLE_MIRI + dev_types.push_back("miri"); +#endif #ifdef ENABLE_SDRPLAY dev_types.push_back("sdrplay"); #endif @@ -151,9 +157,6 @@ source_impl::source_impl( const std::string &args ) #ifdef ENABLE_AIRSPY dev_types.push_back("airspy"); #endif -#ifdef ENABLE_AIRSPYHF - dev_types.push_back("airspyhf"); -#endif #ifdef ENABLE_SOAPY dev_types.push_back("soapy"); #endif @@ -163,14 +166,11 @@ source_impl::source_impl( const std::string &args ) #ifdef ENABLE_FREESRP dev_types.push_back("freesrp"); #endif -#ifdef ENABLE_XTRX - dev_types.push_back("xtrx"); -#endif std::cerr << "gr-osmosdr " << GR_OSMOSDR_VERSION << " (" << GR_OSMOSDR_LIBVER << ") " << "gnuradio " << gr::version() << std::endl; std::cerr << "built-in source types: "; - for (std::string dev_type : dev_types) + BOOST_FOREACH(std::string dev_type, dev_types) std::cerr << dev_type << " "; std::cerr << std::endl; @@ -181,9 +181,9 @@ source_impl::source_impl( const std::string &args ) dev_types.push_back("cloudiq"); #endif - for (std::string arg : arg_list) { + BOOST_FOREACH(std::string arg, arg_list) { dict_t dict = params_to_dict(arg); - for (std::string dev_type : dev_types) { + BOOST_FOREACH(std::string dev_type, dev_types) { if ( dict.count( dev_type ) ) { device_specified = true; break; @@ -191,63 +191,76 @@ source_impl::source_impl( const std::string &args ) } } + bool force_arg = false; + int force_val = 0; + + if (arg_list.size() <= 2) { + BOOST_FOREACH(std::string arg, arg_list) { + if ( arg.find( "numchan=" ) == 0 ) { + pair_t pair = param_to_pair( arg ); + force_arg = true; + force_val = boost::lexical_cast<size_t>( pair.second ); + } + } + } + if ( ! device_specified ) { std::vector< std::string > dev_list; +#ifdef ENABLE_OSMOSDR + BOOST_FOREACH( std::string dev, osmosdr_src_c::get_devices() ) + dev_list.push_back( dev ); +#endif #ifdef ENABLE_FCD - for (std::string dev : fcd_source_c::get_devices()) + BOOST_FOREACH( std::string dev, fcd_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_RTL - for (std::string dev : rtl_source_c::get_devices()) + BOOST_FOREACH( std::string dev, rtl_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_UHD - for (std::string dev : uhd_source_c::get_devices()) + BOOST_FOREACH( std::string dev, uhd_source_c::get_devices() ) + dev_list.push_back( dev ); +#endif +#ifdef ENABLE_MIRI + BOOST_FOREACH( std::string dev, miri_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_SDRPLAY - for (std::string dev : sdrplay_source_c::get_devices()) + BOOST_FOREACH( std::string dev, sdrplay_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_BLADERF - for (std::string dev : bladerf_source_c::get_devices()) + BOOST_FOREACH( std::string dev, bladerf_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_RFSPACE - for (std::string dev : rfspace_source_c::get_devices()) + BOOST_FOREACH( std::string dev, rfspace_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_HACKRF - for (std::string dev : hackrf_source_c::get_devices()) + BOOST_FOREACH( std::string dev, hackrf_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_AIRSPY - for (std::string dev : airspy_source_c::get_devices()) - dev_list.push_back( dev ); -#endif -#ifdef ENABLE_AIRSPYHF - for (std::string dev : airspyhf_source_c::get_devices()) + BOOST_FOREACH( std::string dev, airspy_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_SOAPY - for (std::string dev : soapy_source_c::get_devices()) + BOOST_FOREACH( std::string dev, soapy_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_REDPITAYA - for (std::string dev : redpitaya_source_c::get_devices()) + BOOST_FOREACH( std::string dev, redpitaya_source_c::get_devices() ) dev_list.push_back( dev ); #endif #ifdef ENABLE_FREESRP - for (std::string dev : freesrp_source_c::get_devices()) - dev_list.push_back( dev ); -#endif -#ifdef ENABLE_XTRX - for (std::string dev : xtrx_source_c::get_devices()) + BOOST_FOREACH( std::string dev, freesrp_source_c::get_devices() ) dev_list.push_back( dev ); #endif // std::cerr << std::endl; -// for (std::string dev : dev_list) +// BOOST_FOREACH( std::string dev, dev_list ) // std::cerr << "'" << dev << "'" << std::endl; if ( dev_list.size() ) @@ -256,17 +269,27 @@ source_impl::source_impl( const std::string &args ) throw std::runtime_error("No supported devices found (check the connection and/or udev rules)."); } - for (std::string arg : arg_list) { + BOOST_FOREACH(std::string arg, arg_list) { + + if(force_arg) + arg += ",nchan=" + std::to_string(force_val); dict_t dict = params_to_dict(arg); // std::cerr << std::endl; -// for (dict_t::value_type &entry : dict) +// BOOST_FOREACH( dict_t::value_type &entry, dict ) // std::cerr << "'" << entry.first << "' = '" << entry.second << "'" << std::endl; source_iface *iface = NULL; gr::basic_block_sptr block; +#ifdef ENABLE_OSMOSDR + if ( dict.count("osmosdr") ) { + osmosdr_src_c_sptr src = osmosdr_make_src_c( arg ); + block = src; iface = src.get(); + } +#endif + #ifdef ENABLE_FCD if ( dict.count("fcd") ) { fcd_source_c_sptr src = make_fcd_source_c( arg ); @@ -302,6 +325,13 @@ source_impl::source_impl( const std::string &args ) } #endif +#ifdef ENABLE_MIRI + if ( dict.count("miri") ) { + miri_source_c_sptr src = make_miri_source_c( arg ); + block = src; iface = src.get(); + } +#endif + #ifdef ENABLE_SDRPLAY if ( dict.count("sdrplay") ) { sdrplay_source_c_sptr src = make_sdrplay_source_c( arg ); @@ -341,13 +371,6 @@ source_impl::source_impl( const std::string &args ) } #endif -#ifdef ENABLE_AIRSPYHF - if ( dict.count("airspyhf") ) { - airspyhf_source_c_sptr src = make_airspyhf_source_c( arg ); - block = src; iface = src.get(); - } -#endif - #ifdef ENABLE_SOAPY if ( dict.count("soapy") ) { soapy_source_c_sptr src = make_soapy_source_c( arg ); @@ -369,13 +392,6 @@ source_impl::source_impl( const std::string &args ) } #endif -#ifdef ENABLE_XTRX - if ( dict.count("xtrx") ) { - xtrx_source_c_sptr src = make_xtrx_source_c( arg ); - block = src; iface = src.get(); - } -#endif - if ( iface != NULL && long(block.get()) != 0 ) { _devs.push_back( iface ); @@ -403,13 +419,20 @@ source_impl::source_impl( const std::string &args ) if (!_devs.size()) throw std::runtime_error("No devices specified via device arguments."); + + /* Populate the _gain and _gain_mode arrays with the hardware state */ + BOOST_FOREACH( source_iface *dev, _devs ) + for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { + _gain_mode[dev_chan] = dev->get_gain_mode(dev_chan); + _gain[dev_chan] = dev->get_gain(dev_chan); + } } size_t source_impl::get_num_channels() { size_t channels = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) channels += dev->get_num_channels(); return channels; @@ -418,7 +441,7 @@ size_t source_impl::get_num_channels() bool source_impl::seek( long seek_point, int whence, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->seek( seek_point, whence, dev_chan ); @@ -448,12 +471,12 @@ double source_impl::set_sample_rate(double rate) if (_devs.empty()) throw std::runtime_error(NO_DEVICES_MSG); #endif - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) sample_rate = dev->set_sample_rate(rate); #ifdef HAVE_IQBALANCE size_t channel = 0; - for (source_iface *dev : _devs) { + BOOST_FOREACH( source_iface *dev, _devs ) { for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { if ( channel < _iq_opt.size() ) { gr::iqbalance::optimize_c *opt = _iq_opt[channel]; @@ -472,7 +495,7 @@ double source_impl::set_sample_rate(double rate) _sample_rate = sample_rate; } - return _sample_rate; + return sample_rate; } double source_impl::get_sample_rate() @@ -491,7 +514,7 @@ double source_impl::get_sample_rate() osmosdr::freq_range_t source_impl::get_freq_range( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_freq_range( dev_chan ); @@ -502,7 +525,7 @@ osmosdr::freq_range_t source_impl::get_freq_range( size_t chan ) double source_impl::set_center_freq( double freq, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _center_freq[ chan ] != freq ) { @@ -517,7 +540,7 @@ double source_impl::set_center_freq( double freq, size_t chan ) double source_impl::get_center_freq( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_center_freq( dev_chan ); @@ -528,7 +551,7 @@ double source_impl::get_center_freq( size_t chan ) double source_impl::set_freq_corr( double ppm, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _freq_corr[ chan ] != ppm ) { @@ -543,7 +566,7 @@ double source_impl::set_freq_corr( double ppm, size_t chan ) double source_impl::get_freq_corr( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_freq_corr( dev_chan ); @@ -554,7 +577,7 @@ double source_impl::get_freq_corr( size_t chan ) std::vector<std::string> source_impl::get_gain_names( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_names( dev_chan ); @@ -565,7 +588,7 @@ std::vector<std::string> source_impl::get_gain_names( size_t chan ) osmosdr::gain_range_t source_impl::get_gain_range( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_range( dev_chan ); @@ -576,7 +599,7 @@ osmosdr::gain_range_t source_impl::get_gain_range( size_t chan ) osmosdr::gain_range_t source_impl::get_gain_range( const std::string & name, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_range( name, dev_chan ); @@ -587,7 +610,7 @@ osmosdr::gain_range_t source_impl::get_gain_range( const std::string & name, siz bool source_impl::set_gain_mode( bool automatic, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _gain_mode[ chan ] != automatic ) { @@ -605,7 +628,7 @@ bool source_impl::set_gain_mode( bool automatic, size_t chan ) bool source_impl::get_gain_mode( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain_mode( dev_chan ); @@ -616,7 +639,7 @@ bool source_impl::get_gain_mode( size_t chan ) double source_impl::set_gain( double gain, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _gain[ chan ] != gain ) { @@ -631,7 +654,7 @@ double source_impl::set_gain( double gain, size_t chan ) double source_impl::set_gain( double gain, const std::string & name, size_t chan) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->set_gain( gain, name, dev_chan ); @@ -642,7 +665,7 @@ double source_impl::set_gain( double gain, const std::string & name, size_t chan double source_impl::get_gain( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain( dev_chan ); @@ -653,7 +676,7 @@ double source_impl::get_gain( size_t chan ) double source_impl::get_gain( const std::string & name, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_gain( name, dev_chan ); @@ -664,7 +687,7 @@ double source_impl::get_gain( const std::string & name, size_t chan ) double source_impl::set_if_gain( double gain, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _if_gain[ chan ] != gain ) { @@ -679,7 +702,7 @@ double source_impl::set_if_gain( double gain, size_t chan ) double source_impl::set_bb_gain( double gain, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _bb_gain[ chan ] != gain ) { @@ -694,7 +717,7 @@ double source_impl::set_bb_gain( double gain, size_t chan ) std::vector< std::string > source_impl::get_antennas( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_antennas( dev_chan ); @@ -705,7 +728,7 @@ std::vector< std::string > source_impl::get_antennas( size_t chan ) std::string source_impl::set_antenna( const std::string & antenna, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _antenna[ chan ] != antenna ) { @@ -720,7 +743,7 @@ std::string source_impl::set_antenna( const std::string & antenna, size_t chan ) std::string source_impl::get_antenna( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_antenna( dev_chan ); @@ -731,7 +754,7 @@ std::string source_impl::get_antenna( size_t chan ) void source_impl::set_dc_offset_mode( int mode, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) dev->set_dc_offset_mode( mode, dev_chan ); @@ -740,7 +763,7 @@ void source_impl::set_dc_offset_mode( int mode, size_t chan ) void source_impl::set_dc_offset( const std::complex<double> &offset, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) dev->set_dc_offset( offset, dev_chan ); @@ -750,7 +773,7 @@ void source_impl::set_iq_balance_mode( int mode, size_t chan ) { size_t channel = 0; #ifdef HAVE_IQBALANCE - for (source_iface *dev : _devs) { + BOOST_FOREACH( source_iface *dev, _devs ) { for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { if ( chan == channel++ ) { if ( chan < _iq_opt.size() && chan < _iq_fix.size() ) { @@ -780,7 +803,7 @@ void source_impl::set_iq_balance_mode( int mode, size_t chan ) } } #else - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->set_iq_balance_mode( mode, dev_chan ); @@ -791,7 +814,7 @@ void source_impl::set_iq_balance( const std::complex<double> &balance, size_t ch { size_t channel = 0; #ifdef HAVE_IQBALANCE - for (source_iface *dev : _devs) { + BOOST_FOREACH( source_iface *dev, _devs ) { for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) { if ( chan == channel++ ) { if ( chan < _iq_opt.size() && chan < _iq_fix.size() ) { @@ -807,7 +830,7 @@ void source_impl::set_iq_balance( const std::complex<double> &balance, size_t ch } } #else - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->set_iq_balance( balance, dev_chan ); @@ -817,7 +840,7 @@ void source_impl::set_iq_balance( const std::complex<double> &balance, size_t ch double source_impl::set_bandwidth( double bandwidth, size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) { if ( _bandwidth[ chan ] != bandwidth || 0.0f == bandwidth ) { @@ -832,7 +855,7 @@ double source_impl::set_bandwidth( double bandwidth, size_t chan ) double source_impl::get_bandwidth( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_bandwidth( dev_chan ); @@ -843,7 +866,7 @@ double source_impl::get_bandwidth( size_t chan ) osmosdr::freq_range_t source_impl::get_bandwidth_range( size_t chan ) { size_t channel = 0; - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) return dev->get_bandwidth_range( dev_chan ); @@ -936,7 +959,7 @@ void source_impl::set_time_now(const osmosdr::time_spec_t &time_spec, size_t mbo void source_impl::set_time_next_pps(const osmosdr::time_spec_t &time_spec) { - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) { dev->set_time_next_pps( time_spec ); } @@ -944,7 +967,7 @@ void source_impl::set_time_next_pps(const osmosdr::time_spec_t &time_spec) void source_impl::set_time_unknown_pps(const osmosdr::time_spec_t &time_spec) { - for (source_iface *dev : _devs) + BOOST_FOREACH( source_iface *dev, _devs ) { dev->set_time_unknown_pps( time_spec ); } diff --git a/lib/uhd/CMakeLists.txt b/lib/uhd/CMakeLists.txt index 0ab6508..aba5c77 100644 --- a/lib/uhd/CMakeLists.txt +++ b/lib/uhd/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2012 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. @@ -21,19 +21,19 @@ # This file included, use CMake directory variables ######################################################################## -target_include_directories(gnuradio-osmosdr PRIVATE +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} - ${gnuradio-uhd_INCLUDE_DIRS} + ${GNURADIO_UHD_INCLUDE_DIRS} ${UHD_INCLUDE_DIRS} ) -APPEND_LIB_LIST( - gnuradio::gnuradio-uhd - ${UHD_LIBRARIES} -) - -list(APPEND gr_osmosdr_srcs +set(uhd_srcs ${CMAKE_CURRENT_SOURCE_DIR}/uhd_sink_c.cc ${CMAKE_CURRENT_SOURCE_DIR}/uhd_source_c.cc ) -set(gr_osmosdr_srcs ${gr_osmosdr_srcs} PARENT_SCOPE) + +######################################################################## +# Append gnuradio-osmosdr library sources +######################################################################## +list(APPEND gr_osmosdr_srcs ${uhd_srcs}) +list(APPEND gr_osmosdr_libs ${GNURADIO_UHD_LIBRARIES} ${UHD_LIBRARIES}) diff --git a/lib/uhd/uhd_sink_c.cc b/lib/uhd/uhd_sink_c.cc index 8698f4c..a154556 100644 --- a/lib/uhd/uhd_sink_c.cc +++ b/lib/uhd/uhd_sink_c.cc @@ -18,6 +18,7 @@ * Boston, MA 02110-1301, USA. */ +#include <boost/foreach.hpp> #include <boost/assign.hpp> #include <boost/algorithm/string.hpp> @@ -70,7 +71,7 @@ uhd_sink_c::uhd_sink_c(const std::string &args) : _lo_offset = boost::lexical_cast< double >( dict["lo_offset"] ); std::string arguments; // rebuild argument string without internal arguments - for (dict_t::value_type &entry : dict) + BOOST_FOREACH( dict_t::value_type &entry, dict ) { if ( "cpu_format" == entry.first || "otw_format" == entry.first || @@ -134,7 +135,7 @@ std::vector< std::string > uhd_sink_c::get_devices() std::vector< std::string > devices; uhd::device_addr_t hint; - for (const uhd::device_addr_t &dev : uhd::device::find(hint)) + BOOST_FOREACH(const uhd::device_addr_t &dev, uhd::device::find(hint)) { std::string args = "uhd," + dev.to_string(); @@ -189,7 +190,7 @@ osmosdr::meta_range_t uhd_sink_c::get_sample_rates( void ) { osmosdr::meta_range_t rates; - for (uhd::range_t rate : _snk->get_samp_rates()) + BOOST_FOREACH( uhd::range_t rate, _snk->get_samp_rates() ) rates += osmosdr::range_t( rate.start(), rate.stop(), rate.step() ); return rates; @@ -210,7 +211,7 @@ osmosdr::freq_range_t uhd_sink_c::get_freq_range( size_t chan ) { osmosdr::freq_range_t range; - for (uhd::range_t freq : _snk->get_freq_range(chan)) + BOOST_FOREACH( uhd::range_t freq, _snk->get_freq_range(chan) ) range += osmosdr::range_t( freq.start(), freq.stop(), freq.step() ); return range; @@ -259,7 +260,7 @@ osmosdr::gain_range_t uhd_sink_c::get_gain_range( size_t chan ) { osmosdr::gain_range_t range; - for (uhd::range_t gain : _snk->get_gain_range(chan)) + BOOST_FOREACH( uhd::range_t gain, _snk->get_gain_range(chan) ) range += osmosdr::range_t( gain.start(), gain.stop(), gain.step() ); return range; @@ -269,7 +270,7 @@ osmosdr::gain_range_t uhd_sink_c::get_gain_range( const std::string & name, size { osmosdr::gain_range_t range; - for (uhd::range_t gain : _snk->get_gain_range(name, chan)) + BOOST_FOREACH( uhd::range_t gain, _snk->get_gain_range(name, chan) ) range += osmosdr::range_t( gain.start(), gain.stop(), gain.step() ); return range; @@ -350,7 +351,7 @@ osmosdr::freq_range_t uhd_sink_c::get_bandwidth_range( size_t chan ) { osmosdr::freq_range_t bandwidths; - for (uhd::range_t bw : _snk->get_bandwidth_range(chan)) + BOOST_FOREACH( uhd::range_t bw, _snk->get_bandwidth_range(chan) ) bandwidths += osmosdr::range_t( bw.start(), bw.stop(), bw.step() ); return bandwidths; diff --git a/lib/uhd/uhd_source_c.cc b/lib/uhd/uhd_source_c.cc index f9f9fdd..fc13017 100644 --- a/lib/uhd/uhd_source_c.cc +++ b/lib/uhd/uhd_source_c.cc @@ -18,6 +18,7 @@ * Boston, MA 02110-1301, USA. */ +#include <boost/foreach.hpp> #include <boost/assign.hpp> #include <boost/algorithm/string.hpp> @@ -71,7 +72,7 @@ uhd_source_c::uhd_source_c(const std::string &args) : _lo_offset = boost::lexical_cast< double >( dict["lo_offset"] ); std::string arguments; // rebuild argument string without internal arguments - for (dict_t::value_type &entry : dict) + BOOST_FOREACH( dict_t::value_type &entry, dict ) { if ( "cpu_format" == entry.first || "otw_format" == entry.first || @@ -135,7 +136,7 @@ std::vector< std::string > uhd_source_c::get_devices() std::vector< std::string > devices; uhd::device_addr_t hint; - for (const uhd::device_addr_t &dev : uhd::device::find(hint)) + BOOST_FOREACH(const uhd::device_addr_t &dev, uhd::device::find(hint)) { std::string args = "uhd," + dev.to_string(); @@ -190,7 +191,7 @@ osmosdr::meta_range_t uhd_source_c::get_sample_rates( void ) { osmosdr::meta_range_t rates; - for (uhd::range_t rate : _src->get_samp_rates()) + BOOST_FOREACH( uhd::range_t rate, _src->get_samp_rates() ) rates += osmosdr::range_t( rate.start(), rate.stop(), rate.step() ); return rates; @@ -211,7 +212,7 @@ osmosdr::freq_range_t uhd_source_c::get_freq_range( size_t chan ) { osmosdr::freq_range_t range; - for (uhd::range_t freq : _src->get_freq_range(chan)) + BOOST_FOREACH( uhd::range_t freq, _src->get_freq_range(chan) ) range += osmosdr::range_t( freq.start(), freq.stop(), freq.step() ); return range; @@ -260,7 +261,7 @@ osmosdr::gain_range_t uhd_source_c::get_gain_range( size_t chan ) { osmosdr::gain_range_t range; - for (uhd::range_t gain : _src->get_gain_range(chan)) + BOOST_FOREACH( uhd::range_t gain, _src->get_gain_range(chan) ) range += osmosdr::range_t( gain.start(), gain.stop(), gain.step() ); return range; @@ -270,7 +271,7 @@ osmosdr::gain_range_t uhd_source_c::get_gain_range( const std::string & name, si { osmosdr::gain_range_t range; - for (uhd::range_t gain : _src->get_gain_range(name, chan)) + BOOST_FOREACH( uhd::range_t gain, _src->get_gain_range(name, chan) ) range += osmosdr::range_t( gain.start(), gain.stop(), gain.step() ); return range; @@ -382,7 +383,7 @@ osmosdr::freq_range_t uhd_source_c::get_bandwidth_range( size_t chan ) { osmosdr::freq_range_t bandwidths; - for (uhd::range_t bw : _src->get_bandwidth_range(chan)) + BOOST_FOREACH( uhd::range_t bw, _src->get_bandwidth_range(chan) ) bandwidths += osmosdr::range_t( bw.start(), bw.stop(), bw.step() ); return bandwidths; diff --git a/lib/xtrx/xtrx_obj.cc b/lib/xtrx/xtrx_obj.cc deleted file mode 100644 index 016b420..0000000 --- a/lib/xtrx/xtrx_obj.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2017 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#include "xtrx_obj.h" -#include <iostream> -#include <sstream> -#include <boost/thread.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/mutex.hpp> - -static std::map<std::string, xtrx_obj_sptr> s_objects; - -xtrx_obj_sptr xtrx_obj::get(const char* xtrx_dev, - unsigned loglevel, - bool lmsreset) -{ - std::map<std::string, xtrx_obj_sptr>::iterator i; - std::string name(xtrx_dev); - - i = s_objects.find(name); - if (i == s_objects.end()) { - // No such object - s_objects[name].reset(new xtrx_obj(name, loglevel, lmsreset)); - } - - return s_objects[name]; -} - -void xtrx_obj::clear_all() -{ - s_objects.clear(); -} - -std::vector<std::string> xtrx_obj::get_devices() -{ - std::vector<std::string> devices; - // TODO - devices.push_back("/dev/xtrx0"); - return devices; -} - - -xtrx_obj::xtrx_obj(const std::string &path, unsigned loglevel, bool lmsreset) - : _run(false) - , _vio(0) - , _sink_rate(0) - , _sink_master(0) - , _source_rate(0) - , _source_master(0) - , _flags(0) -{ - unsigned xtrxflag = (loglevel & XTRX_O_LOGLVL_MASK) | ((lmsreset) ? XTRX_O_RESET : 0); - std::cerr << "xtrx_obj::xtrx_obj = " << xtrxflag << std::endl; - - int res = xtrx_open_string(path.c_str(), &_obj); - if (res < 0) { - std::stringstream message; - message << "Couldn't open " ": Error: " << -res; - - throw std::runtime_error( message.str() ); - } - - _devices = res; -} - -double xtrx_obj::set_smaplerate(double rate, double master, bool sink, unsigned flags) -{ - boost::mutex::scoped_lock lock(mtx); - - if (sink) { - _sink_rate = rate; - _sink_master = master; - } else { - _source_rate = rate; - _source_master = master; - } - _flags |= flags | XTRX_SAMPLERATE_FORCE_UPDATE; - - if (_sink_master != 0 && _source_master != 0 && _sink_master != _source_master) { - std::stringstream message; - message << "Can't operate on diferrent master settings for XTRX sink and source" - " sink_master " << _sink_master << " source_master" << _source_master; - - throw std::runtime_error( message.str() ); - } - - double rxrate = 0, txrate = 0; - double actmaster = (_source_master > 0) ? _source_master : _sink_master; - int res = xtrx_set_samplerate(_obj, - actmaster, - _source_rate, - _sink_rate, - _flags, - NULL, - &rxrate, - &txrate); - if (res) { - std::cerr << "Unable to set samplerate, error=" << res << std::endl; - if (sink) - return _sink_rate; - return _source_rate; - } - - if (_vio) { - xtrx_val_set(_obj, XTRX_TRX, XTRX_CH_AB, XTRX_LMS7_VIO, _vio); - } - - if (sink) - return txrate; - return rxrate; -} - -xtrx_obj::~xtrx_obj() -{ - if (_obj) { - if (_run) { - //boost::mutex::scoped_lock lock(mtx); - xtrx_stop(_obj, XTRX_TRX); - } - xtrx_close(_obj); - } -} diff --git a/lib/xtrx/xtrx_obj.h b/lib/xtrx/xtrx_obj.h deleted file mode 100644 index e26947d..0000000 --- a/lib/xtrx/xtrx_obj.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2017 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef XTRX_OBJ_H -#define XTRX_OBJ_H - -#include <boost/shared_ptr.hpp> -#include <xtrx_api.h> -#include <map> -#include <vector> -#include <boost/thread/mutex.hpp> - -class xtrx_obj; - -typedef boost::shared_ptr<xtrx_obj> xtrx_obj_sptr; - -class xtrx_obj -{ -public: - xtrx_obj(const std::string& path, unsigned loglevel, bool lmsreset); - ~xtrx_obj(); - - static std::vector<std::string> get_devices(); - - static xtrx_obj_sptr get(const char* xtrx_dev, - unsigned loglevel, - bool lmsreset); - static void clear_all(); - - xtrx_dev* dev() { return _obj; } - unsigned dev_count() { return _devices; } - - double set_smaplerate(double rate, double master, bool sink, unsigned flags); - - void set_vio(unsigned vio) { _vio = vio; } - - boost::mutex mtx; -protected: - xtrx_dev* _obj; - bool _run; - unsigned _vio; - - double _sink_rate; - double _sink_master; - double _source_rate; - double _source_master; - - unsigned _flags; - unsigned _devices; -}; - -#endif // XTRX_OBJ_H diff --git a/lib/xtrx/xtrx_sink_c.cc b/lib/xtrx/xtrx_sink_c.cc deleted file mode 100644 index 5253311..0000000 --- a/lib/xtrx/xtrx_sink_c.cc +++ /dev/null @@ -1,505 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2016,2017 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#include <fstream> -#include <string> -#include <sstream> -#include <map> - -#include <boost/assign.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/thread.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/mutex.hpp> - -#include <gnuradio/io_signature.h> -#include <gnuradio/blocks/deinterleave.h> -#include <gnuradio/blocks/float_to_complex.h> - -#include "xtrx_sink_c.h" - -#include "arg_helpers.h" - -static const int max_burstsz = 4096; -using namespace boost::assign; - -xtrx_sink_c_sptr make_xtrx_sink_c(const std::string &args) -{ - return gnuradio::get_initial_sptr(new xtrx_sink_c(args)); -} - -static size_t parse_nchan(const std::string &args) -{ - size_t nchan = 1; - - dict_t dict = params_to_dict(args); - - if (dict.count("nchan")) - nchan = boost::lexical_cast< size_t >( dict["nchan"] ); - - if (nchan < 1) - nchan = 1; - - return nchan; -} - -xtrx_sink_c::xtrx_sink_c(const std::string &args) : - gr::sync_block("xtrx_sink_c", - gr::io_signature::make(parse_nchan(args), - parse_nchan(args), - sizeof(gr_complex)), - gr::io_signature::make(0, 0, 0)), - _sample_flags(0), - _rate(0), - _master(0), - _freq(0), - _corr(0), - _bandwidth(0), - _dsp(0), - _auto_gain(false), - _otw(XTRX_WF_16), - _mimo_mode(false), - _gain_tx(0), - _channels(parse_nchan(args)), - _ts(8192), - _swap_ab(false), - _swap_iq(false), - _tdd(false), - _allow_dis(false), - _dev("") -{ - - dict_t dict = params_to_dict(args); - - if (dict.count("master")) { - _master = boost::lexical_cast< double >( dict["master"]); - } - - std::cerr << args.c_str() << std::endl; - - int loglevel = 4; - if (dict.count("loglevel")) { - loglevel = boost::lexical_cast< int >( dict["loglevel"] ); - } - - bool lmsreset = 0; - if (dict.count("lmsreset")) { - lmsreset = boost::lexical_cast< bool >( dict["lmsreset"] ); - } - - if (dict.count("txdelay")) { - _ts += 8192 * boost::lexical_cast< int >( dict["txdelay"] ); - } - - if (dict.count("allowdis")) { - _allow_dis = boost::lexical_cast< bool >( dict["allowdis"] ); - } - - if (dict.count("swap_ab")) { - _swap_ab = true; - std::cerr << "xtrx_sink_c: swap AB channels"; - } - - if (dict.count("swap_iq")) { - _swap_iq = true; - std::cerr << "xtrx_sink_c: swap IQ"; - } - - if (dict.count("sfl")) { - _sample_flags = boost::lexical_cast< unsigned >( dict["sfl"] ); - } - - if (dict.count("tdd")) { - _tdd = true; - std::cerr << "xtrx_sink_c: TDD mode"; - } - - if (dict.count("dsp")) { - _dsp = boost::lexical_cast< double >( dict["dsp"] ); - std::cerr << "xtrx_sink_c: DSP:" << _dsp; - } - - if (dict.count("dev")) { - _dev = dict["dev"]; - std::cerr << "xtrx_sink_c: XTRX device: %s" << _dev.c_str(); - } - - _xtrx = xtrx_obj::get(_dev.c_str(), loglevel, lmsreset); - if (_xtrx->dev_count() * 2 == _channels) { - _mimo_mode = true; - } else if (_xtrx->dev_count() != _channels) { - throw std::runtime_error("Number of requested channels != number of devices"); - } - if (dict.count("refclk")) { - xtrx_set_ref_clk(_xtrx->dev(), boost::lexical_cast< unsigned >( dict["refclk"] ), XTRX_CLKSRC_INT); - } - if (dict.count("extclk")) { - xtrx_set_ref_clk(_xtrx->dev(), boost::lexical_cast< unsigned >( dict["extclk"] ), XTRX_CLKSRC_EXT); - } - - std::cerr << "xtrx_sink_c::xtrx_sink_c()" << std::endl; - set_alignment(32); - set_output_multiple(max_burstsz); -} - -xtrx_sink_c::~xtrx_sink_c() -{ - std::cerr << "xtrx_sink_c::~xtrx_sink_c()" << std::endl; -} - -std::string xtrx_sink_c::name() -{ - return "GrLibXTRX"; -} - -size_t xtrx_sink_c::get_num_channels( void ) -{ - return input_signature()->max_streams(); -} - -osmosdr::meta_range_t xtrx_sink_c::get_sample_rates( void ) -{ - osmosdr::meta_range_t range; - range += osmosdr::range_t( 1000000, 160000000, 1 ); - return range; -} - -double xtrx_sink_c::set_sample_rate( double rate ) -{ - std::cerr << "Set sample rate " << rate << std::endl; - _rate = _xtrx->set_smaplerate(rate, _master, true, _sample_flags); - return get_sample_rate(); -} - -double xtrx_sink_c::get_sample_rate( void ) -{ - return _rate; -} - -osmosdr::freq_range_t xtrx_sink_c::get_freq_range( size_t chan ) -{ - osmosdr::freq_range_t range; - range += osmosdr::range_t( double(0.03e9), double(3.8e9), 1); // as far as we know - return range; -} - -double xtrx_sink_c::set_center_freq( double freq, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - _freq = freq; - double corr_freq = (freq)*(1.0 + (_corr) * 0.000001); - - std::cerr << "TX Set freq " << freq << std::endl; - xtrx_channel_t xchan = (xtrx_channel_t)(XTRX_CH_A << chan); - - int res = xtrx_tune_ex(_xtrx->dev(), (_tdd) ? XTRX_TUNE_TX_AND_RX_TDD : XTRX_TUNE_TX_FDD, xchan, corr_freq - _dsp, &_freq); - if (res) { - std::cerr << "Unable to deliver frequency " << corr_freq << std::endl; - } - - res = xtrx_tune_ex(_xtrx->dev(), XTRX_TUNE_BB_TX, xchan, _dsp, NULL); - return get_center_freq(chan); -} - -double xtrx_sink_c::get_center_freq( size_t chan ) -{ - return _freq + _dsp; -} - -double xtrx_sink_c::set_freq_corr( double ppm, size_t chan ) -{ - _corr = ppm; - - set_center_freq(_freq, chan); - - return get_freq_corr( chan ); -} - -double xtrx_sink_c::get_freq_corr( size_t chan ) -{ - return _corr; -} - - -static const std::vector<std::string> s_lna_list = boost::assign::list_of("TX"); - -std::vector<std::string> xtrx_sink_c::get_gain_names( size_t chan ) -{ - return s_lna_list; -} - -osmosdr::gain_range_t xtrx_sink_c::get_gain_range( size_t chan ) -{ - return get_gain_range("TX", chan); -} - -osmosdr::gain_range_t xtrx_sink_c::get_gain_range( const std::string & name, size_t chan ) -{ - osmosdr::gain_range_t range; - range += osmosdr::range_t( -31, 0, 1 ); - return range; -} - -bool xtrx_sink_c::set_gain_mode( bool automatic, size_t chan ) -{ - _auto_gain = automatic; - return get_gain_mode(chan); -} - -bool xtrx_sink_c::get_gain_mode( size_t chan ) -{ - return _auto_gain; -} - -double xtrx_sink_c::set_gain( double gain, size_t chan ) -{ - return set_gain(gain, "TX", chan); -} - -double xtrx_sink_c::set_gain( double igain, const std::string & name, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - osmosdr::gain_range_t gains = xtrx_sink_c::get_gain_range( name, chan ); - double gain = gains.clip(igain); - double actual_gain; - - std::cerr << "Set TX gain: " << igain << std::endl; - - int res = xtrx_set_gain(_xtrx->dev(), (xtrx_channel_t)(XTRX_CH_A << chan), - XTRX_TX_PAD_GAIN, gain, &actual_gain); - if (res) { - std::cerr << "Unable to set gain `" << name.c_str() << "`; err=" << res << std::endl; - } - - _gain_tx = actual_gain; - return actual_gain; -} - -double xtrx_sink_c::get_gain( size_t chan ) -{ - return get_gain("TX"); -} - -double xtrx_sink_c::get_gain( const std::string & name, size_t chan ) -{ - return _gain_tx; -} - -double xtrx_sink_c::set_bandwidth( double bandwidth, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - std::cerr << "Set bandwidth " << bandwidth << " chan " << chan << std::endl; - - if (bandwidth <= 0.0) { - bandwidth = get_sample_rate() * 0.75; - if (bandwidth < 0.5e6) { - bandwidth = 0.5e6; - } - } - - int res = xtrx_tune_tx_bandwidth(_xtrx->dev(), - (xtrx_channel_t)(XTRX_CH_A << chan), - bandwidth, &_bandwidth); - if (res) { - std::cerr << "Can't set bandwidth: " << res << std::endl; - } - return get_bandwidth(chan); -} - -double xtrx_sink_c::get_bandwidth( size_t chan ) -{ - return _bandwidth; -} - - -static const std::map<std::string, xtrx_antenna_t> s_ant_map = boost::assign::map_list_of - ("AUTO", XTRX_TX_AUTO) - ("B1", XTRX_TX_H) - ("B2", XTRX_TX_W) - ("TXH", XTRX_TX_H) - ("TXW", XTRX_TX_W) - ; -static const std::map<xtrx_antenna_t, std::string> s_ant_map_r = boost::assign::map_list_of - (XTRX_TX_H, "TXH") - (XTRX_TX_W, "TXW") - (XTRX_TX_AUTO, "AUTO") - ; - -static xtrx_antenna_t get_ant_type(const std::string& name) -{ - std::map<std::string, xtrx_antenna_t>::const_iterator it; - - it = s_ant_map.find(name); - if (it != s_ant_map.end()) { - return it->second; - } - - return XTRX_TX_AUTO; -} - -static const std::vector<std::string> s_ant_list = boost::assign::list_of - ("AUTO")("TXH")("TXW") - ; - - -std::vector< std::string > xtrx_sink_c::get_antennas( size_t chan ) -{ - return s_ant_list; -} - -std::string xtrx_sink_c::set_antenna( const std::string & antenna, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - _ant = get_ant_type(antenna); - - std::cerr << "Set antenna " << antenna << std::endl; - - int res = xtrx_set_antenna_ex(_xtrx->dev(), - (xtrx_channel_t)(XTRX_CH_A << chan), - _ant); - if (res) { - std::cerr << "Can't set antenna: " << antenna << std::endl; - } - return get_antenna( chan ); -} - -std::string xtrx_sink_c::get_antenna( size_t chan ) -{ - return s_ant_map_r.find(_ant)->second; -} - -void xtrx_sink_c::tag_process(int ninput_items) -{ - std::sort(_tags.begin(), _tags.end(), gr::tag_t::offset_compare); - - const uint64_t samp0_count = this->nitems_read(0); - uint64_t max_count = samp0_count + ninput_items; - - bool found_time_tag = false; - for (const gr::tag_t &my_tag : _tags) { - const uint64_t my_tag_count = my_tag.offset; - const pmt::pmt_t &key = my_tag.key; - const pmt::pmt_t &value = my_tag.value; - - if (my_tag_count >= max_count) { - break; - } else if(pmt::equal(key, TIME_KEY)) { - //if (my_tag_count != samp0_count) { - // max_count = my_tag_count; - // break; - //} - found_time_tag = true; - //_metadata.has_time_spec = true; - //_metadata.time_spec = ::uhd::time_spec_t - // (pmt::to_uint64(pmt::tuple_ref(value, 0)), - // pmt::to_double(pmt::tuple_ref(value, 1))); - uint64_t seconds = pmt::to_uint64(pmt::tuple_ref(value, 0)); - double fractional = pmt::to_double(pmt::tuple_ref(value, 1)); - - std::cerr << "TX_TIME: " << seconds << ":" << fractional << std::endl; - } - } // end for - - if (found_time_tag) { - //_metadata.has_time_spec = true; - } -} - -int xtrx_sink_c::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - int ninput_items = noutput_items; - const uint64_t samp0_count = nitems_read(0); - get_tags_in_range(_tags, 0, samp0_count, samp0_count + ninput_items); - if (!_tags.empty()) - tag_process(ninput_items); - - xtrx_send_ex_info_t nfo; - nfo.samples = noutput_items; - nfo.buffer_count = input_items.size(); - nfo.buffers = &input_items[0]; - nfo.flags = XTRX_TX_DONT_BUFFER; - if (!_allow_dis) - nfo.flags |= XTRX_TX_NO_DISCARD; - nfo.ts = _ts; - nfo.timeout = 0; - - int res = xtrx_send_sync_ex(_xtrx->dev(), &nfo); - if (res) { - std::cerr << "Err: " << res << std::endl; - - std::stringstream message; - message << "xtrx_send_burst_sync error: " << -res; - throw std::runtime_error( message.str() ); - } - - _ts += noutput_items; - for (unsigned i = 0; i < input_items.size(); i++) { - consume(i, noutput_items); - } - return 0; -} - -bool xtrx_sink_c::start() -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - xtrx_run_params_t params; - xtrx_run_params_init(¶ms); - - params.dir = XTRX_TX; - if (!_mimo_mode) - params.tx.flags |= XTRX_RSP_SISO_MODE; - - if (_swap_ab) - params.tx.flags |= XTRX_RSP_SWAP_AB; - - if (_swap_iq) - params.tx.flags |= XTRX_RSP_SWAP_IQ; - - params.tx.hfmt = XTRX_IQ_FLOAT32; - params.tx.wfmt = _otw; - params.tx.chs = XTRX_CH_AB; - params.tx.paketsize = 0; - params.rx_stream_start = 256*1024; - - int res = xtrx_run_ex(_xtrx->dev(), ¶ms); - if (res) { - std::cerr << "Got error: " << res << std::endl; - } - - return res == 0; -} - -bool xtrx_sink_c::stop() -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - //TODO: - std::cerr << "xtrx_sink_c::stop()" << std::endl; - int res = xtrx_stop(_xtrx->dev(), XTRX_TX); - if (res) { - std::cerr << "Got error: " << res << std::endl; - } - - return res == 0; -} diff --git a/lib/xtrx/xtrx_sink_c.h b/lib/xtrx/xtrx_sink_c.h deleted file mode 100644 index 1263858..0000000 --- a/lib/xtrx/xtrx_sink_c.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2016 Sergey Kostanabev <sergey.kostanbaev@fairwaves.co> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef XTRX_SINK_C_H -#define XTRX_SINK_C_H - -#include <gnuradio/block.h> -#include <gnuradio/sync_block.h> - -#include "sink_iface.h" -#include "xtrx_obj.h" - - -static const pmt::pmt_t SOB_KEY = pmt::string_to_symbol("tx_sob"); -static const pmt::pmt_t EOB_KEY = pmt::string_to_symbol("tx_eob"); -static const pmt::pmt_t TIME_KEY = pmt::string_to_symbol("tx_time"); -static const pmt::pmt_t FREQ_KEY = pmt::string_to_symbol("tx_freq"); -static const pmt::pmt_t COMMAND_KEY = pmt::string_to_symbol("tx_command"); - -class xtrx_sink_c; - -typedef boost::shared_ptr< xtrx_sink_c > xtrx_sink_c_sptr; - -xtrx_sink_c_sptr make_xtrx_sink_c( const std::string & args = "" ); - -class xtrx_sink_c : - public gr::sync_block, - public sink_iface -{ -private: - friend xtrx_sink_c_sptr make_xtrx_sink_c(const std::string &args); - - xtrx_sink_c(const std::string &args); - -public: - ~xtrx_sink_c(); - - std::string name(); - - static std::vector< std::string > get_devices( bool fake = false ) { return xtrx_obj::get_devices(); } - - size_t get_num_channels( void ); - - osmosdr::meta_range_t get_sample_rates( void ); - double set_sample_rate( double rate ); - double get_sample_rate( void ); - - osmosdr::freq_range_t get_freq_range( size_t chan = 0 ); - double set_center_freq( double freq, size_t chan = 0 ); - double get_center_freq( size_t chan = 0 ); - double set_freq_corr( double ppm, size_t chan = 0 ); - double get_freq_corr( size_t chan = 0 ); - - std::vector<std::string> get_gain_names( size_t chan = 0 ); - osmosdr::gain_range_t get_gain_range( size_t chan = 0 ); - osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 ); - bool set_gain_mode( bool automatic, size_t chan = 0 ); - bool get_gain_mode( size_t chan = 0 ); - double set_gain( double gain, size_t chan = 0 ); - double set_gain( double gain, const std::string & name, size_t chan = 0 ); - double get_gain( size_t chan = 0 ); - double get_gain( const std::string & name, size_t chan = 0 ); - - std::vector< std::string > get_antennas( size_t chan = 0 ); - std::string set_antenna( const std::string & antenna, size_t chan = 0 ); - std::string get_antenna( size_t chan = 0 ); - - double set_bandwidth( double bandwidth, size_t chan = 0 ); - double get_bandwidth( size_t chan = 0 ); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - bool start(); - bool stop(); - - void tag_process(int ninput_items); - -private: - xtrx_obj_sptr _xtrx; - std::vector<gr::tag_t> _tags; - - unsigned _sample_flags; - double _rate; - double _master; - double _freq; - double _corr; - double _bandwidth; - double _dsp; - bool _auto_gain; - - xtrx_wire_format_t _otw; - bool _mimo_mode; - - int _gain_tx; - - unsigned _channels; - xtrx_antenna_t _ant; - - uint64_t _ts; - - bool _swap_ab; - bool _swap_iq; - - bool _tdd; - bool _allow_dis; - - std::string _dev; -}; - -#endif // xtrx_sink_c_H diff --git a/lib/xtrx/xtrx_source_c.cc b/lib/xtrx/xtrx_source_c.cc deleted file mode 100644 index 4fdc877..0000000 --- a/lib/xtrx/xtrx_source_c.cc +++ /dev/null @@ -1,583 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2016,2017 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#include <fstream> -#include <string> -#include <sstream> -#include <map> - -#include <boost/assign.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/thread.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/mutex.hpp> - -#include <gnuradio/io_signature.h> -#include <gnuradio/blocks/deinterleave.h> -#include <gnuradio/blocks/float_to_complex.h> - -#include "xtrx_source_c.h" - -#include "arg_helpers.h" - -using namespace boost::assign; - - -xtrx_source_c_sptr make_xtrx_source_c(const std::string &args) -{ - return gnuradio::get_initial_sptr(new xtrx_source_c(args)); -} - -static size_t parse_nchan(const std::string &args) -{ - size_t nchan = 1; - - dict_t dict = params_to_dict(args); - - if (dict.count("nchan")) - nchan = boost::lexical_cast< size_t >( dict["nchan"] ); - - if (nchan < 1) - nchan = 1; - - return nchan; -} - -xtrx_source_c::xtrx_source_c(const std::string &args) : - gr::sync_block("xtrx_source_c", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(parse_nchan(args), - parse_nchan(args), - sizeof(gr_complex))), - _sample_flags(0), - _rate(0), - _master(0), - _freq(0), - _corr(0), - _bandwidth(0), - _auto_gain(false), - _otw(XTRX_WF_16), - _mimo_mode(false), - _gain_lna(0), - _gain_tia(0), - _gain_pga(0), - _channels(parse_nchan(args)), - _swap_ab(false), - _swap_iq(false), - _loopback(false), - _tdd(false), - _fbctrl(false), - _timekey(false), - _dsp(0) -{ - _id = pmt::string_to_symbol(args); - - dict_t dict = params_to_dict(args); - - if (dict.count("otw_format")) { - const std::string& otw = dict["otw_format"]; - if (otw == "sc16" || otw == "16") { - _otw = XTRX_WF_16; - } else if (otw == "sc12" || otw == "12") { - _otw = XTRX_WF_12; - } else if (otw == "sc8" || otw == "8") { - _otw = XTRX_WF_8; - } else { - throw std::runtime_error("Parameter `otw_format` should be {sc16,sc12,sc8}"); - } - } - - if (dict.count("master")) { - _master = boost::lexical_cast< double >( dict["master"]); - } - - std::cerr << args.c_str() << std::endl; - - int loglevel = 4; - if (dict.count("loglevel")) { - loglevel = boost::lexical_cast< int >( dict["loglevel"] ); - } - - bool lmsreset = 0; - if (dict.count("lmsreset")) { - lmsreset = boost::lexical_cast< bool >( dict["lmsreset"] ); - } - - if (dict.count("fbctrl")) { - _fbctrl = boost::lexical_cast< bool >( dict["fbctrl"] ); - } - - if (dict.count("swap_ab")) { - _swap_ab = true; - std::cerr << "xtrx_source_c: swap AB channels"; - } - - if (dict.count("swap_iq")) { - _swap_iq = true; - std::cerr << "xtrx_source_c: swap IQ"; - } - - if (dict.count("sfl")) { - _sample_flags = boost::lexical_cast< unsigned >( dict["sfl"] ); - } - - if (dict.count("loopback")) { - _loopback = true; - std::cerr << "xtrx_source_c: loopback"; - } - - if (dict.count("tdd")) { - _tdd = true; - std::cerr << "xtrx_source_c: TDD mode"; - } - - if (dict.count("dsp")) { - _dsp = boost::lexical_cast< double >( dict["dsp"] ); - std::cerr << "xtrx_source_c: DSP:" << _dsp; - } - - if (dict.count("dev")) { - _dev = dict["dev"]; - std::cerr << "xtrx_source_c: XTRX device: %s" << _dev.c_str(); - } - - _xtrx = xtrx_obj::get(_dev.c_str(), loglevel, lmsreset); - if (_xtrx->dev_count() * 2 == _channels) { - _mimo_mode = true; - } else if (_xtrx->dev_count() != _channels) { - throw std::runtime_error("Number of requested channels != number of devices"); - } - - if (dict.count("refclk")) { - xtrx_set_ref_clk(_xtrx->dev(), boost::lexical_cast< unsigned >( dict["refclk"] ), XTRX_CLKSRC_INT); - } - if (dict.count("extclk")) { - xtrx_set_ref_clk(_xtrx->dev(), boost::lexical_cast< unsigned >( dict["extclk"] ), XTRX_CLKSRC_EXT); - } - - if (dict.count("vio")) { - unsigned vio = boost::lexical_cast< unsigned >( dict["vio"] ); - _xtrx->set_vio(vio); - } - - if (dict.count("dac")) { - unsigned dac = boost::lexical_cast< unsigned >( dict["dac"] ); - xtrx_val_set(_xtrx->dev(), XTRX_TRX, XTRX_CH_ALL, XTRX_VCTCXO_DAC_VAL, dac); - } - - if (dict.count("pmode")) { - unsigned pmode = boost::lexical_cast< unsigned >( dict["pmode"] ); - xtrx_val_set(_xtrx->dev(), XTRX_TRX, XTRX_CH_ALL, XTRX_LMS7_PWR_MODE, pmode); - } - - if (dict.count("timekey")) { - _timekey = boost::lexical_cast< bool >( dict["timekey"] ); - } - - std::cerr << "xtrx_source_c::xtrx_source_c()" << std::endl; - set_alignment(32); - if (_otw == XTRX_WF_16) { - if (_mimo_mode) - set_output_multiple(4096); - else - set_output_multiple(8192); - } else if (_otw == XTRX_WF_8) { - if (_mimo_mode) - set_output_multiple(8192); - else - set_output_multiple(16384); - } -} - -xtrx_source_c::~xtrx_source_c() -{ - std::cerr << "xtrx_source_c::~xtrx_source_c()" << std::endl; -} - -std::string xtrx_source_c::name() -{ - return "GrLibXTRX"; -} - -size_t xtrx_source_c::get_num_channels( void ) -{ - return output_signature()->max_streams(); -} - -osmosdr::meta_range_t xtrx_source_c::get_sample_rates( void ) -{ - osmosdr::meta_range_t range; - range += osmosdr::range_t( 200000, 160000000, 1 ); - return range; -} - -double xtrx_source_c::set_sample_rate( double rate ) -{ - std::cerr << "Set sample rate " << rate << std::endl; - _rate = _xtrx->set_smaplerate(rate, _master, false, _sample_flags); - return get_sample_rate(); -} - -double xtrx_source_c::get_sample_rate( void ) -{ - return _rate; -} - -osmosdr::freq_range_t xtrx_source_c::get_freq_range( size_t chan ) -{ - osmosdr::freq_range_t range; - range += osmosdr::range_t( double(0.03e9), double(3.8e9), 1); // as far as we know - return range; -} - -double xtrx_source_c::set_center_freq( double freq, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - _freq = freq; - double corr_freq = (freq)*(1.0 + (_corr) * 0.000001); - - if (_tdd) - return get_center_freq(chan); - - xtrx_channel_t xchan = (xtrx_channel_t)(XTRX_CH_A << chan); - - std::cerr << "Set freq " << freq << std::endl; - - int res = xtrx_tune_ex(_xtrx->dev(), XTRX_TUNE_RX_FDD, xchan, corr_freq - _dsp, &_freq); - if (res) { - std::cerr << "Unable to deliver frequency " << corr_freq << std::endl; - } - - res = xtrx_tune_ex(_xtrx->dev(), XTRX_TUNE_BB_RX, xchan, _dsp, NULL); - - return get_center_freq(chan); -} - -double xtrx_source_c::get_center_freq( size_t chan ) -{ - return _freq; -} - -double xtrx_source_c::set_freq_corr( double ppm, size_t chan ) -{ - _corr = ppm; - - set_center_freq(_freq, chan); - - return get_freq_corr( chan ); -} - -double xtrx_source_c::get_freq_corr( size_t chan ) -{ - return _corr; -} - -static const std::map<std::string, xtrx_gain_type_t> s_lna_map = boost::assign::map_list_of - ("LNA", XTRX_RX_LNA_GAIN) - ("TIA", XTRX_RX_TIA_GAIN) - ("PGA", XTRX_RX_PGA_GAIN) - ("LB", XTRX_RX_LB_GAIN) - ; - -static xtrx_gain_type_t get_gain_type(const std::string& name) -{ - std::map<std::string, xtrx_gain_type_t>::const_iterator it; - - it = s_lna_map.find(name); - if (it != s_lna_map.end()) { - return it->second; - } - - return XTRX_RX_LNA_GAIN; -} - -static const std::vector<std::string> s_lna_list = boost::assign::list_of - ("LNA")("TIA")("PGA")("LB") - ; - -std::vector<std::string> xtrx_source_c::get_gain_names( size_t chan ) -{ - return s_lna_list; -} - -osmosdr::gain_range_t xtrx_source_c::get_gain_range( size_t chan ) -{ - return get_gain_range("LNA", chan); -} - -osmosdr::gain_range_t xtrx_source_c::get_gain_range( const std::string & name, size_t chan ) -{ - osmosdr::gain_range_t range; - - if (name == "LNA") { - range += osmosdr::range_t( 0, 24, 3 ); - range += osmosdr::range_t( 25, 30, 1 ); - } else if (name == "TIA") { - range += osmosdr::range_t( 0 ); - range += osmosdr::range_t( 9 ); - range += osmosdr::range_t( 12 ); - } else if (name == "PGA") { - range += osmosdr::range_t( -12.5, 12.5, 1 ); - } else if (name == "LB") { - range += osmosdr::range_t( -40, 0, 1 ); - } - - return range; -} - -bool xtrx_source_c::set_gain_mode( bool automatic, size_t chan ) -{ - _auto_gain = automatic; - return get_gain_mode(chan); -} - -bool xtrx_source_c::get_gain_mode( size_t chan ) -{ - return _auto_gain; -} - -double xtrx_source_c::set_gain( double gain, size_t chan ) -{ - return set_gain(gain, "LNA", chan); -} - -double xtrx_source_c::set_gain( double igain, const std::string & name, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - osmosdr::gain_range_t gains = xtrx_source_c::get_gain_range( name, chan ); - double gain = gains.clip(igain); - double actual_gain; - xtrx_gain_type_t gt = get_gain_type(name); - - std::cerr << "Set gain " << name << " (" << gt << "): " << igain << std::endl; - - int res = xtrx_set_gain(_xtrx->dev(), (xtrx_channel_t)(XTRX_CH_A << chan), - gt, gain, &actual_gain); - if (res) { - std::cerr << "Unable to set gain `" << name.c_str() << "`; err=" << res << std::endl; - } - - switch (gt) { - case XTRX_RX_LNA_GAIN: _gain_lna = actual_gain; break; - case XTRX_RX_TIA_GAIN: _gain_tia = actual_gain; break; - case XTRX_RX_PGA_GAIN: _gain_pga = actual_gain; break; - default: break; - } - - return actual_gain; -} - -double xtrx_source_c::get_gain( size_t chan ) -{ - return get_gain("LNA"); -} - -double xtrx_source_c::get_gain( const std::string & name, size_t chan ) -{ - xtrx_gain_type_t gt = get_gain_type(name); - switch (gt) { - case XTRX_RX_LNA_GAIN: return _gain_lna; - case XTRX_RX_TIA_GAIN: return _gain_tia; - case XTRX_RX_PGA_GAIN: return _gain_pga; - default: return 0; - } -} - -double xtrx_source_c::set_if_gain(double gain, size_t chan) -{ - return set_gain(gain, "PGA", chan); -} - -double xtrx_source_c::set_bandwidth( double bandwidth, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - std::cerr << "Set bandwidth " << bandwidth << " chan " << chan << std::endl; - - if (bandwidth <= 0.0) { - bandwidth = get_sample_rate() * 0.75; - if (bandwidth < 0.5e6) { - bandwidth = 0.5e6; - } - } - - int res = xtrx_tune_rx_bandwidth(_xtrx->dev(), (xtrx_channel_t)(XTRX_CH_A << chan), - bandwidth, &_bandwidth); - if (res) { - std::cerr << "Can't set bandwidth: " << res << std::endl; - } - return get_bandwidth(chan); -} - -double xtrx_source_c::get_bandwidth( size_t chan ) -{ - return _bandwidth; -} - -osmosdr::freq_range_t xtrx_source_c::get_bandwidth_range( size_t chan ) -{ - return osmosdr::freq_range_t(500e3, 140e6, 0); -} - - -static const std::map<std::string, xtrx_antenna_t> s_ant_map = boost::assign::map_list_of - ("AUTO", XTRX_RX_AUTO) - ("RXL", XTRX_RX_L) - ("RXH", XTRX_RX_H) - ("RXW", XTRX_RX_W) - ("RXL_LB", XTRX_RX_L_LB) - ("RXW_LB", XTRX_RX_W_LB) - ; -static const std::map<xtrx_antenna_t, std::string> s_ant_map_r = boost::assign::map_list_of - (XTRX_RX_AUTO, "AUTO") - (XTRX_RX_L, "RXL") - (XTRX_RX_H, "RXH") - (XTRX_RX_W, "RXW") - (XTRX_RX_L_LB, "RXL_LB") - (XTRX_RX_W_LB, "RXW_LB") - ; - -static xtrx_antenna_t get_ant_type(const std::string& name) -{ - std::map<std::string, xtrx_antenna_t>::const_iterator it; - - it = s_ant_map.find(name); - if (it != s_ant_map.end()) { - return it->second; - } - - return XTRX_RX_AUTO; -} - -static const std::vector<std::string> s_ant_list = boost::assign::list_of - ("AUTO")("RXL")("RXH")("RXW") - ; - - -std::vector< std::string > xtrx_source_c::get_antennas( size_t chan ) -{ - return s_ant_list; -} - -std::string xtrx_source_c::set_antenna( const std::string & antenna, size_t chan ) -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - _ant = get_ant_type(antenna); - - std::cerr << "Set antenna " << antenna << " type:" << _ant << std::endl; - - int res = xtrx_set_antenna_ex(_xtrx->dev(), (xtrx_channel_t)(XTRX_CH_A << chan), - _ant); - if (res) { - std::cerr << "Can't set antenna: " << antenna << std::endl; - } - return get_antenna( chan ); -} - -std::string xtrx_source_c::get_antenna( size_t chan ) -{ - return s_ant_map_r.find(_ant)->second; -} - -int xtrx_source_c::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - xtrx_recv_ex_info_t ri; - ri.samples = noutput_items; - ri.buffer_count = output_items.size(); - ri.buffers = &output_items[0]; - ri.flags = RCVEX_DONT_INSER_ZEROS | RCVEX_DROP_OLD_ON_OVERFLOW; - ri.timeout = 1000; - - int res = xtrx_recv_sync_ex(_xtrx->dev(), &ri); - if (res) { - std::stringstream message; - message << "xtrx_recv_sync error: " << -res; - throw std::runtime_error( message.str() ); - } - - if (_timekey) { - uint64_t seconds = (ri.out_first_sample / _rate); - double fractional = (ri.out_first_sample - (uint64_t)(_rate * seconds)) / _rate; - - //std::cerr << "Time " << seconds << ":" << fractional << std::endl; - const pmt::pmt_t val = pmt::make_tuple - (pmt::from_uint64(seconds), - pmt::from_double(fractional)); - for(size_t i = 0; i < output_items.size(); i++) { - this->add_item_tag(i, nitems_written(0), TIME_KEY, - val, _id); - this->add_item_tag(i, nitems_written(0), RATE_KEY, - pmt::from_double(_rate), _id); - this->add_item_tag(i, nitems_written(0), FREQ_KEY, - pmt::from_double(this->get_center_freq(i)), _id); - } - } - return ri.out_samples; -} - -bool xtrx_source_c::start() -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - - xtrx_run_params_t params; - xtrx_run_params_init(¶ms); - - params.dir = XTRX_RX; - if (!_mimo_mode) - params.rx.flags |= XTRX_RSP_SISO_MODE; - - if (_swap_ab) - params.rx.flags |= XTRX_RSP_SWAP_AB; - - if (_swap_iq) - params.rx.flags |= XTRX_RSP_SWAP_IQ; - - params.rx.hfmt = XTRX_IQ_FLOAT32; - params.rx.wfmt = _otw; - params.rx.chs = XTRX_CH_AB; - params.rx.paketsize = 0; - params.rx_stream_start = 256*1024; - - params.nflags = (_loopback) ? XTRX_RUN_DIGLOOPBACK : 0; - - int res = xtrx_run_ex(_xtrx->dev(), ¶ms); - if (res) { - std::cerr << "Got error: " << res << std::endl; - } - - res = xtrx_tune_ex(_xtrx->dev(), XTRX_TUNE_BB_RX, XTRX_CH_ALL, _dsp, NULL); - - return res == 0; -} - -bool xtrx_source_c::stop() -{ - boost::mutex::scoped_lock lock(_xtrx->mtx); - //TODO: - std::cerr << "xtrx_source_c::stop()" << std::endl; - int res = xtrx_stop(_xtrx->dev(), XTRX_RX); - if (res) { - std::cerr << "Got error: " << res << std::endl; - } - - return res == 0; -} diff --git a/lib/xtrx/xtrx_source_c.h b/lib/xtrx/xtrx_source_c.h deleted file mode 100644 index fda9d77..0000000 --- a/lib/xtrx/xtrx_source_c.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2016,2017 Sergey Kostanbaev <sergey.kostanbaev@fairwaves.co> - * - * GNU Radio 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, or (at your option) - * any later version. - * - * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef XTRX_SOURCE_C_H -#define XTRX_SOURCE_C_H - -#include <gnuradio/block.h> -#include <gnuradio/sync_block.h> - -#include "source_iface.h" -#include "xtrx_obj.h" - -static const pmt::pmt_t TIME_KEY = pmt::string_to_symbol("rx_time"); -static const pmt::pmt_t RATE_KEY = pmt::string_to_symbol("rx_rate"); -static const pmt::pmt_t FREQ_KEY = pmt::string_to_symbol("rx_freq"); - -class xtrx_source_c; - -typedef boost::shared_ptr< xtrx_source_c > xtrx_source_c_sptr; - -xtrx_source_c_sptr make_xtrx_source_c( const std::string & args = "" ); - -class xtrx_source_c : - public gr::sync_block, - public source_iface -{ -private: - friend xtrx_source_c_sptr make_xtrx_source_c(const std::string &args); - - xtrx_source_c(const std::string &args); - -public: - ~xtrx_source_c(); - - std::string name(); - - static std::vector< std::string > get_devices( bool fake = false ) { return xtrx_obj::get_devices(); } - - size_t get_num_channels( void ); - - osmosdr::meta_range_t get_sample_rates( void ); - double set_sample_rate( double rate ); - double get_sample_rate( void ); - - osmosdr::freq_range_t get_freq_range( size_t chan = 0 ); - double set_center_freq( double freq, size_t chan = 0 ); - double get_center_freq( size_t chan = 0 ); - double set_freq_corr( double ppm, size_t chan = 0 ); - double get_freq_corr( size_t chan = 0 ); - - std::vector<std::string> get_gain_names( size_t chan = 0 ); - osmosdr::gain_range_t get_gain_range( size_t chan = 0 ); - osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 ); - bool set_gain_mode( bool automatic, size_t chan = 0 ); - bool get_gain_mode( size_t chan = 0 ); - double set_gain( double gain, size_t chan = 0 ); - double set_gain( double gain, const std::string & name, size_t chan = 0 ); - double get_gain( size_t chan = 0 ); - double get_gain( const std::string & name, size_t chan = 0 ); - - double set_if_gain( double gain, size_t chan = 0 ); - - std::vector< std::string > get_antennas( size_t chan = 0 ); - std::string set_antenna( const std::string & antenna, size_t chan = 0 ); - std::string get_antenna( size_t chan = 0 ); - - double set_bandwidth( double bandwidth, size_t chan = 0 ); - double get_bandwidth( size_t chan = 0 ); - osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - bool start(); - bool stop(); - -private: - xtrx_obj_sptr _xtrx; - pmt::pmt_t _id; - - unsigned _sample_flags; - double _rate; - double _master; - double _freq; - double _corr; - double _bandwidth; - bool _auto_gain; - - xtrx_wire_format_t _otw; - bool _mimo_mode; - - int _gain_lna; - int _gain_tia; - int _gain_pga; - - unsigned _channels; - xtrx_antenna_t _ant; - - bool _swap_ab; - bool _swap_iq; - bool _loopback; - bool _tdd; - bool _fbctrl; - bool _timekey; - - double _dsp; - std::string _dev; -}; - -#endif // XTRX_SOURCE_C_H diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 53cb61e..8841f36 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,19 +1,19 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. diff --git a/python/__init__.py b/python/__init__.py index 1cb090f..70c469d 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -22,4 +22,15 @@ This is the GNU Radio OsmoSDR module. ''' -from .osmosdr_swig import * +from __future__ import unicode_literals + +# import swig generated symbols into the osmosdr namespace +try: + # this might fail if the module is python-only + from .osmosdr_swig import * +except ImportError as ie: + print(ie) + pass + +# import any pure python here +# diff --git a/swig/CMakeLists.txt b/swig/CMakeLists.txt index 159f212..d01d029 100644 --- a/swig/CMakeLists.txt +++ b/swig/CMakeLists.txt @@ -1,27 +1,35 @@ # Copyright 2011 Free Software Foundation, Inc. # -# This file is part of gr-osmosdr +# This file is part of GNU Radio # -# gr-osmosdr is free software; you can redistribute it and/or modify +# GNU Radio 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, or (at your option) # any later version. # -# gr-osmosdr is distributed in the hope that it will be useful, +# GNU Radio 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 gr-osmosdr; see the file COPYING. If not, write to +# along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. ######################################################################## +# Check if there is C++ code at all +######################################################################## +#if(NOT osmosdr_sources) +# MESSAGE(STATUS "No C++ sources... skipping swig/") +# return() +#endif(NOT osmosdr_sources) + +######################################################################## # Include swig generation macros ######################################################################## find_package(SWIG) -find_package(PythonLibs 3) +find_package(PythonLibs) if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND) return() endif() @@ -31,13 +39,16 @@ include(GrPython) ######################################################################## # Setup swig generation ######################################################################## +foreach(incdir ${GNURADIO_ALL_INCLUDE_DIRS}) + list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gnuradio/swig) +endforeach(incdir) set(GR_SWIG_INCLUDE_DIRS $<TARGET_PROPERTY:gnuradio::runtime_swig,INTERFACE_INCLUDE_DIRECTORIES>) set(GR_SWIG_TARGET_DEPS gnuradio::runtime_swig) set(GR_SWIG_LIBRARIES gnuradio-osmosdr) set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/osmosdr_swig_doc.i) -set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include/osmosdr) +set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include) GR_SWIG_MAKE(osmosdr_swig osmosdr_swig.i) |