diff --git a/CMakeLists.txt b/CMakeLists.txt index 82f37c8..4264a8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required (VERSION 2.8) SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MINOR "1") -SET(CUBICSDR_VERSION_PATCH "6") -SET(CUBICSDR_VERSION_REL "beta-issue140") +SET(CUBICSDR_VERSION_PATCH "7") +SET(CUBICSDR_VERSION_REL "beta-issue64") SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}") SET(CPACK_PACKAGE_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}") @@ -15,9 +15,9 @@ ADD_DEFINITIONS( -DCUBICSDR_VERSION="${CUBICSDR_VERSION}" ) -IF (NOT APPLE) +# IF (NOT APPLE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") -ENDIF(NOT APPLE) +# ENDIF(NOT APPLE) macro(configure_files srcDir destDir globStr) @@ -80,11 +80,31 @@ SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_BINARY_DIR}/${EX_PLATFORM_NA SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_BINARY_DIR}/${EX_PLATFORM_NAME}) find_package(OpenGL REQUIRED) +IF (NOT WIN32) +find_package(FFTW REQUIRED) +find_package(Liquid REQUIRED) +include_directories(${LIQUID_INCLUDES} ${FFTW_INCLUDES}) +SET(OTHER_LIBRARIES ${OTHER_LIBRARIES} ${LIQUID_LIBRARIES} ${FFTW_LIBRARIES}) +ENDIF() find_package(wxWidgets COMPONENTS gl core base REQUIRED) set(wxWidgets_CONFIGURATION mswu) include(${wxWidgets_USE_FILE}) +SET(USE_SOAPY_SDR ON CACHE BOOL "Build with SoapySDR support instead of RTL-SDR.") +IF (USE_SOAPY_SDR) + find_package(SoapySDR NO_MODULE REQUIRED) + include_directories(${SOAPY_SDR_INCLUDE_DIR}) + SET(OTHER_LIBRARIES ${SOAPY_SDR_LIBRARY} ${OTHER_LIBRARIES}) + ADD_DEFINITIONS( + -DUSE_SOAPY_SDR=1 + ) +ELSE() + SET(USE_RTL_SDR ON CACHE BOOL "Build with RTL-SDR support only.") + ADD_DEFINITIONS( + -DUSE_RTL_SDR=1 + ) +ENDIF() IF (WIN32) set(wxWidgets_USE_STATIC ON) @@ -121,11 +141,16 @@ IF (WIN32) #ENDIF(USE_AUDIO_ASIO) # FFTW - include_directories ( ${PROJECT_SOURCE_DIR}/external/fftw-3.3.4 ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release ) + include_directories ( ${PROJECT_SOURCE_DIR}/external/fftw-3.3.4 ) set(FFTW_LIB libfftw3f-3) + link_directories ( ${PROJECT_SOURCE_DIR}/external/fftw-3.3.4/${EX_PLATFORM} ) configure_files(${PROJECT_SOURCE_DIR}/external/fftw-3.3.4/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") + IF(USE_RTL_SDR) + include_directories( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release ) + ENDIF() + include_directories ( ${PROJECT_SOURCE_DIR}/external/liquid-dsp/include ) set(LIQUID_LIB libliquid) @@ -135,15 +160,19 @@ IF (WIN32) link_directories ( ${PROJECT_SOURCE_DIR}/external/liquid-dsp/msvc/${EX_PLATFORM} ) configure_files(${PROJECT_SOURCE_DIR}/external/liquid-dsp/msvc/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME}/ "*.dll") # RTL-SDR - link_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM} ) - configure_files(${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") + IF(USE_RTL_SDR) + link_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM} ) + configure_files(${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") + ENDIF() ELSE (MSVC) # GCC # LIQUID link_directories ( ${PROJECT_SOURCE_DIR}/external/liquid-dsp/gcc/${EX_PLATFORM} ) configure_files(${PROJECT_SOURCE_DIR}/external/liquid-dsp/gcc/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") # RTL-SDR - link_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM} ) - configure_files(${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") + IF(USE_RTL_SDR) + link_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM} ) + configure_files(${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") + ENDIF() ENDIF(MSVC) # Copy DLL files to build dir @@ -154,18 +183,20 @@ ENDIF (WIN32) IF (UNIX AND NOT APPLE) set(BUILD_DEB OFF CACHE BOOL "Build DEB") - set(RTLSDR_INCLUDE "/usr/local/include" CACHE FILEPATH "RTL-SDR Include Path") - set(RTLSDR_LIB "/usr/local/lib" CACHE FILEPATH "RTL-SDR Lib Path") - set(USE_AUDIO_PULSE ON CACHE BOOL "Use Pulse Audio") - set(USE_AUDIO_JACK OFF CACHE BOOL "Use Jack Audio") - set(USE_AUDIO_ALSA OFF CACHE BOOL "Use ALSA Audio") - set(USE_AUDIO_OSS OFF CACHE BOOL "Use OSS Audio") - include_directories(${RTLSDR_INCLUDE}) - link_directories(${RTLSDR_LIB}) + IF(USE_RTL_SDR) + SET(RTLSDR_INCLUDE "/usr/local/include" CACHE FILEPATH "RTL-SDR Include Path") + SET(RTLSDR_LIB "/usr/local/lib" CACHE FILEPATH "RTL-SDR Lib Path") + include_directories(${RTLSDR_INCLUDE}) + link_directories(${RTLSDR_LIB}) + ENDIF() + SET(USE_AUDIO_PULSE ON CACHE BOOL "Use Pulse Audio") + SET(USE_AUDIO_JACK OFF CACHE BOOL "Use Jack Audio") + SET(USE_AUDIO_ALSA OFF CACHE BOOL "Use ALSA Audio") + SET(USE_AUDIO_OSS OFF CACHE BOOL "Use OSS Audio") - set(FFTW_LIB fftw3f) - set(LIQUID_LIB liquid) - set(OTHER_LIBRARIES dl) + SET(FFTW_LIB fftw3f) + SET(LIQUID_LIB liquid) + SET(OTHER_LIBRARIES ${OTHER_LIBRARIES} dl) IF(USE_AUDIO_PULSE) SET (OTHER_LIBRARIES ${OTHER_LIBRARIES} pulse-simple pulse) @@ -203,21 +234,25 @@ ENDIF(USE_AUDIO_OSS) ENDIF(UNIX AND NOT APPLE) IF (APPLE) - set(RTLSDR_INCLUDE "/opt/local/include" CACHE FILEPATH "RTL-SDR Include Path") - set(RTLSDR_LIB "/opt/local/lib" CACHE FILEPATH "RTL-SDR Lib Path") - include_directories(${RTLSDR_INCLUDE}) - link_directories(${RTLSDR_LIB}) - set(LIB_DIRS "${LIB_DIRS} ${RTLSDR_LIB}") + IF (USE_RTL_SDR) + SET(RTLSDR_INCLUDE "/opt/local/include" CACHE FILEPATH "RTL-SDR Include Path") + SET(RTLSDR_LIB "/opt/local/lib" CACHE FILEPATH "RTL-SDR Lib Path") + include_directories(${RTLSDR_INCLUDE}) + link_directories(${RTLSDR_LIB}) + SET(LIB_DIRS ${LIB_DIRS} ${RTLSDR_LIB}) + ENDIF() - set(FFTW_LIB fftw3f) - set(LIQUID_LIB liquid) + SET(FFTW_LIB fftw3f) + SET(LIQUID_LIB liquid) + link_directories(/usr/local/lib) + link_directories(/opt/local/lib) ADD_DEFINITIONS( -D__MACOSX_CORE__ ) FIND_LIBRARY(COREAUDIO_LIBRARY CoreAudio) - SET (OTHER_LIBRARIES ${COREAUDIO_LIBRARY}) + SET (OTHER_LIBRARIES ${COREAUDIO_LIBRARY} ${OTHER_LIBRARIES}) set(BUNDLE_APP OFF CACHE BOOL "Bundle Application") ENDIF (APPLE) @@ -230,7 +265,6 @@ SET (cubicsdr_sources src/FrequencyDialog.cpp src/IOThread.cpp src/sdr/SDRDeviceInfo.cpp - src/sdr/SDRThread.cpp src/sdr/SDRPostThread.cpp src/demod/DemodulatorPreThread.cpp src/demod/DemodulatorThread.cpp @@ -284,7 +318,6 @@ SET (cubicsdr_headers src/FrequencyDialog.h src/IOThread.h src/sdr/SDRDeviceInfo.h - src/sdr/SDRThread.h src/sdr/SDRPostThread.h src/demod/DemodulatorPreThread.h src/demod/DemodulatorThread.h @@ -347,6 +380,16 @@ SET (cubicsdr_headers external/cubicvr2/math/vec4.h ) + +IF (USE_SOAPY_SDR) + SET(cubicsdr_sources ${cubicsdr_sources} src/SDR/SoapySDRThread.cpp) + SET(cubicsdr_headers ${cubicsdr_headers} src/SDR/SoapySDRThread.h) +ELSE() + SET(cubicsdr_sources ${cubicsdr_sources} src/SDR/SDRThread.cpp) + SET(cubicsdr_headers ${cubicsdr_headers} src/SDR/SDRThread.h) +ENDIF() + + set(REG_EXT "[^/]*([.]cpp|[.]c|[.]h|[.]hpp)$") SOURCE_GROUP("Base" REGULAR_EXPRESSION src/${REG_EXT}) @@ -410,7 +453,10 @@ IF (NOT BUNDLE_APP) configure_files(${PROJECT_SOURCE_DIR}/font ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.png") configure_files(${PROJECT_SOURCE_DIR}/icon ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} CubicSDR.ico) add_executable(CubicSDR ${cubicsdr_sources} ${cubicsdr_headers} ${RES_FILES}) - target_link_libraries(CubicSDR rtlsdr ${LIQUID_LIB} ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${OTHER_LIBRARIES}) + IF (USE_RTL_SDR) + SET(OTHER_LIBRARIES rtlsdr ${OTHER_LIBRARIES}) + ENDIF() + target_link_libraries(CubicSDR ${LIQUID_LIB} ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${OTHER_LIBRARIES}) ENDIF (NOT BUNDLE_APP) IF (MSVC) @@ -479,7 +525,11 @@ IF (APPLE AND BUNDLE_APP) MACOSX_PACKAGE_LOCATION Resources ) - target_link_libraries(CubicSDR rtlsdr ${LIQUID_LIB} ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${OTHER_LIBRARIES}) + IF (USE_RTL_SDR) + SET(OTHER_LIBRARIES rtlsdr ${OTHER_LIBRARIES}) + ENDIF() + + target_link_libraries(CubicSDR ${LIQUID_LIB} ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${OTHER_LIBRARIES}) SET_TARGET_PROPERTIES(CubicSDR PROPERTIES MACOSX_BUNDLE TRUE) SET_TARGET_PROPERTIES(CubicSDR PROPERTIES @@ -498,7 +548,7 @@ IF (APPLE AND BUNDLE_APP) INSTALL(CODE " SET(BU_COPY_FULL_FRAMEWORK_CONTENTS ON) include(BundleUtilities) - fixup_bundle(\"${APPS}\" \"\" \"${RTLSDR_LIB}\") + fixup_bundle(\"${APPS}\" \"\" \"/usr/local/lib\") VERIFY_APP(\"${APPS}\") " COMPONENT Runtime) @@ -550,17 +600,23 @@ IF (WIN32 AND BUILD_INSTALLER) ${PROJECT_SOURCE_DIR}/external/fftw-3.3.4/${EX_PLATFORM}/libfftw3f-3.dll DESTINATION .) IF (MSVC) - install(FILES - ${PROJECT_SOURCE_DIR}/external/liquid-dsp/msvc/${EX_PLATFORM}/libliquid.dll - ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM}/rtlsdr.dll - ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM}/libusb-1.0.dll - DESTINATION .) + IF (USE_RTL_SDR) + SET (OTHER_INSTALL_FILES ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM}/rtlsdr.dll) + ENDIF() + install(FILES + ${PROJECT_SOURCE_DIR}/external/liquid-dsp/msvc/${EX_PLATFORM}/libliquid.dll + ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/msvc/${EX_PLATFORM}/libusb-1.0.dll + ${OTHER_INSTALL_FILES} + DESTINATION .) ELSE (MSVC) - install(FILES - ${PROJECT_SOURCE_DIR}/external/liquid-dsp/gcc/${EX_PLATFORM}/libliquid.dll - ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM}/librtlsdr.dll - ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM}/libusb-1.0.dll - DESTINATION .) + IF (USE_RTL_SDR) + SET (OTHER_INSTALL_FILES ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM}/librtlsdr.dll) + ENDIF() + install(FILES + ${PROJECT_SOURCE_DIR}/external/liquid-dsp/gcc/${EX_PLATFORM}/libliquid.dll + ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/gcc/${EX_PLATFORM}/libusb-1.0.dll + ${OTHER_INSTALL_FILES} + DESTINATION .) ENDIF(MSVC) IF(MSVC AND EX_PLATFORM EQUAL 32) @@ -585,7 +641,10 @@ IF (UNIX AND BUILD_DEB) set(CPACK_GENERATOR DEB) set(CPACK_PACKAGE_NAME "CubicSDR") - SET(CPACK_DEBIAN_PACKAGE_DEPENDS " librtlsdr0, libfftw3-single3, libwxgtk3.0-0, libpulse0") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS " libfftw3-single3, libwxgtk3.0-0, libpulse0") + IF (USE_RTL_SDR) + SET(CPACK_DEBIAN_PACKAGE_DEPENDS " librtlsdr0, ${CPACK_DEBIAN_PACKAGE_DEPENDS}") + ENDIF() SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Charles J. Cliffe ") SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "CubicSDR Software Defined Radio application v${CUBICSDR_VERSION}") SET(CPACK_DEBIAN_PACKAGE_SECTION "comm") diff --git a/cmake/Modules/FindFFTW.cmake b/cmake/Modules/FindFFTW.cmake new file mode 100644 index 0000000..00c3401 --- /dev/null +++ b/cmake/Modules/FindFFTW.cmake @@ -0,0 +1,22 @@ +# - Find FFTW +# Find the native FFTW includes and library +# +# FFTW_INCLUDES - where to find fftw3.h +# FFTW_LIBRARIES - List of libraries when using FFTW. +# FFTW_FOUND - True if FFTW found. + +if (FFTW_INCLUDES) + # Already in cache, be silent + set (FFTW_FIND_QUIETLY TRUE) +endif (FFTW_INCLUDES) + +find_path (FFTW_INCLUDES fftw3.h) + +find_library (FFTW_LIBRARIES NAMES fftw3) + +# handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDES) + +mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDES) diff --git a/cmake/Modules/FindLiquid.cmake b/cmake/Modules/FindLiquid.cmake new file mode 100644 index 0000000..f6f2d24 --- /dev/null +++ b/cmake/Modules/FindLiquid.cmake @@ -0,0 +1,22 @@ +# - Find LIQUID +# Find the native LIQUID includes and library +# +# LIQUID_INCLUDES - where to find LIQUID3.h +# LIQUID_LIBRARIES - List of libraries when using LIQUID. +# LIQUID_FOUND - True if LIQUID found. + +if (LIQUID_INCLUDES) + # Already in cache, be silent + set (LIQUID_FIND_QUIETLY TRUE) +endif (LIQUID_INCLUDES) + +find_path (LIQUID_INCLUDES liquid/liquid.h) + +find_library (LIQUID_LIBRARIES NAMES liquid) + +# handle the QUIETLY and REQUIRED arguments and set LIQUID_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (LIQUID DEFAULT_MSG LIQUID_LIBRARIES LIQUID_INCLUDES) + +mark_as_advanced (LIQUID_LIBRARIES LIQUID_INCLUDES) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index dd83269..9e64638 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -14,7 +14,6 @@ #endif #include -#include "SDRThread.h" #include "DemodulatorMgr.h" #include "AudioThread.h" #include "CubicSDR.h" @@ -284,6 +283,7 @@ AppFrame::AppFrame() : sampleRateMenuItems[wxID_BANDWIDTH_2880M] = menu->AppendRadioItem(wxID_BANDWIDTH_2880M, "2.88M"); // sampleRateMenuItems[wxID_BANDWIDTH_3000M] = menu->AppendRadioItem(wxID_BANDWIDTH_3000M, "3.0M"); sampleRateMenuItems[wxID_BANDWIDTH_3200M] = menu->AppendRadioItem(wxID_BANDWIDTH_3200M, "3.2M"); + sampleRateMenuItems[wxID_BANDWIDTH_MANUAL] = menu->AppendRadioItem(wxID_BANDWIDTH_MANUAL, "Manual Entry"); sampleRateMenuItems[wxID_BANDWIDTH_2400M]->Check(true); @@ -584,6 +584,12 @@ void AppFrame::OnMenu(wxCommandEvent& event) { case wxID_BANDWIDTH_3200M: wxGetApp().setSampleRate(3200000); break; + case wxID_BANDWIDTH_MANUAL: + long bw = wxGetNumberFromUser("Set the bandwidth manually", "Sample Rate (Hz), i.e. 2560000 for 2.56M", "Manual Bandwidth Entry", wxGetApp().getSampleRate(), 250000, 16000000, this); + if (bw != -1) { + wxGetApp().setSampleRate(bw); + } + break; } std::vector *devs = wxGetApp().getDevices(); diff --git a/src/AppFrame.h b/src/AppFrame.h index 58fb5cc..b257628 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -45,6 +45,7 @@ #define wxID_BANDWIDTH_2880M 2161 //#define wxID_BANDWIDTH_3000M 2162 #define wxID_BANDWIDTH_3200M 2163 +#define wxID_BANDWIDTH_MANUAL 2164 #define wxID_DEVICE_ID 3500 diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 15d187f..8d02046 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -97,19 +97,20 @@ bool CubicSDR::OnInit() { std::vector::iterator devs_i; - SDRThread::enumerate_rtl(&devs); +// SDRThread::enumerate_rtl(&devs); + devs = SDRThread::enumerate_devices(); SDRDeviceInfo *dev = NULL; - if (devs.size() > 1) { + if (devs->size() > 1) { wxArrayString choices; - for (devs_i = devs.begin(); devs_i != devs.end(); devs_i++) { + for (devs_i = devs->begin(); devs_i != devs->end(); devs_i++) { std::string devName = (*devs_i)->getName(); if ((*devs_i)->isAvailable()) { - devName.append(": "); - devName.append((*devs_i)->getProduct()); - devName.append(" ["); - devName.append((*devs_i)->getSerial()); - devName.append("]"); +// devName.append(": "); +// devName.append((*devs_i)->getProduct()); +// devName.append(" ["); +// devName.append((*devs_i)->getSerial()); +// devName.append("]"); } else { devName.append(" (In Use?)"); } @@ -121,11 +122,11 @@ bool CubicSDR::OnInit() { return false; } - dev = devs[devId]; + dev = (*devs)[devId]; sdrThread->setDeviceId(devId); - } else if (devs.size() == 1) { - dev = devs[0]; + } else if (devs->size() == 1) { + dev = (*devs)[0]; } if (!dev) { @@ -347,7 +348,7 @@ void CubicSDR::removeDemodulator(DemodulatorInstance *demod) { } std::vector* CubicSDR::getDevices() { - return &devs; + return devs; } void CubicSDR::setDevice(int deviceId) { diff --git a/src/CubicSDR.h b/src/CubicSDR.h index fb84e99..2b53970 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -10,7 +10,11 @@ #include "PrimaryGLContext.h" #include "ThreadQueue.h" -#include "SDRThread.h" +#ifdef USE_RTL_SDR + #include "SDRThread.h" +#else + #include "SoapySDRThread.h" +#endif #include "SDRPostThread.h" #include "AudioThread.h" #include "DemodulatorMgr.h" @@ -86,7 +90,7 @@ private: AppFrame *appframe; AppConfig config; PrimaryGLContext *m_glContext; - std::vector devs; + std::vector *devs; DemodulatorMgr demodMgr; diff --git a/src/sdr/SDRDeviceInfo.cpp b/src/sdr/SDRDeviceInfo.cpp index 992f331..a7014b5 100644 --- a/src/sdr/SDRDeviceInfo.cpp +++ b/src/sdr/SDRDeviceInfo.cpp @@ -1,6 +1,64 @@ #include "SDRDeviceInfo.h" +int SDRDeviceChannel::getChannel() const { + return channel; +} + +void SDRDeviceChannel::setChannel(const int channel) { + this->channel = channel; +} + +bool SDRDeviceChannel::isFullDuplex() { + return fullDuplex; +} + +void SDRDeviceChannel::setFullDuplex(bool fullDuplex) { + this->fullDuplex = fullDuplex; +} + +bool SDRDeviceChannel::isTx() { + return tx; +} + +void SDRDeviceChannel::setTx(bool tx) { + this->tx = tx; +} + +bool SDRDeviceChannel::isRx() { + return rx; +} + +void SDRDeviceChannel::setRx(bool rx) { + this->rx = rx; +} + +const SDRDeviceRange &SDRDeviceChannel::getGain() const { + return rangeGain; +} + +const SDRDeviceRange &SDRDeviceChannel::getLNAGain() const { + return rangeLNA; +} + +const SDRDeviceRange &SDRDeviceChannel::getFreqRange() const { + return rangeFull; +} + +const SDRDeviceRange &SDRDeviceChannel::getRFRange() const { + return rangeRF; +} + +const std::vector &SDRDeviceChannel::getSampleRates() const { + return sampleRates; +} + +const std::vector &SDRDeviceChannel::getFilterBandwidths() const { + return filterBandwidths; +} + + + SDRDeviceInfo::SDRDeviceInfo() : name(""), serial(""), available(false) { } @@ -9,12 +67,20 @@ std::string SDRDeviceInfo::getDeviceId() { std::string deviceId; deviceId.append(getName()); - deviceId.append(" :: "); - deviceId.append(getSerial()); +// deviceId.append(" :: "); +// deviceId.append(getSerial()); return deviceId; } +const int SDRDeviceInfo::getIndex() const { + return index; +} + +void SDRDeviceInfo::setIndex(const int index) { + this->index = index; +} + bool SDRDeviceInfo::isAvailable() const { return available; } @@ -63,3 +129,31 @@ void SDRDeviceInfo::setProduct(const std::string& product) { this->product = product; } +const std::string& SDRDeviceInfo::getDriver() const { + return driver; +} + +void SDRDeviceInfo::setDriver(const std::string& driver) { + this->driver = driver; +} + +const std::string& SDRDeviceInfo::getHardware() const { + return hardware; +} + +void SDRDeviceInfo::setHardware(const std::string& hardware) { + this->hardware = hardware; +} + +bool SDRDeviceInfo::hasTimestamps() const { + return timestamps; +} + +void SDRDeviceInfo::setTimestamps(bool timestamps) { + this->timestamps = timestamps; +} + +std::string SDRDeviceInfo::getDeviceArgs() { + return "driver=" + driver; + //+ "," + getDriver() + "=" + std::to_string(getIndex()); +} diff --git a/src/sdr/SDRDeviceInfo.h b/src/sdr/SDRDeviceInfo.h index 36086ad..c2bdfe3 100644 --- a/src/sdr/SDRDeviceInfo.h +++ b/src/sdr/SDRDeviceInfo.h @@ -1,6 +1,77 @@ #pragma once #include +#include + +/* + ---------------------------------------------------- + -- Device identification + ---------------------------------------------------- + driver=rtl + hardware=rtl + + ---------------------------------------------------- + -- Peripheral summary + ---------------------------------------------------- + Channels: 1 Rx, 0 Tx + Timestamps: NO + + ---------------------------------------------------- + -- RX Channel 0 + ---------------------------------------------------- + Full-duplex: YES + Antennas: RX + Full gain range: [0, 49.6] dB + LNA gain range: [0, 49.6] dB + Full freq range: [24, 1766] MHz + RF freq range: [24, 1766] MHz + CORR freq range: MHz + Sample rates: [0.25, 2.56] MHz + Filter bandwidths: [] MHz +*/ + +class SDRDeviceRange { +public: + SDRDeviceRange(float low, float high); + + float getLow() const; + void setLow(const float low); + float getHigh() const; + void setHigh(const float high); + +private: + float low, high; +}; + +class SDRDeviceChannel { + int getChannel() const; + void setChannel(const int channel); + + bool isFullDuplex(); + void setFullDuplex(bool fullDuplex); + + bool isTx(); + void setTx(bool tx); + + bool isRx(); + void setRx(bool rx); + + const SDRDeviceRange &getGain() const; + const SDRDeviceRange &getLNAGain() const; + const SDRDeviceRange &getFreqRange() const; + const SDRDeviceRange &getRFRange() const; + + const std::vector &getSampleRates() const; + const std::vector &getFilterBandwidths() const; + +private: + int channel; + bool fullDuplex, tx, rx; + SDRDeviceRange rangeGain, rangeLNA, rangeFull, rangeRF; + std::vector sampleRates; + std::vector filterBandwidths; +}; + class SDRDeviceInfo { public: @@ -8,6 +79,9 @@ public: std::string getDeviceId(); + const int getIndex() const; + void setIndex(const int index); + bool isAvailable() const; void setAvailable(bool available); @@ -25,12 +99,24 @@ public: const std::string& getProduct() const; void setProduct(const std::string& product); + + const std::string& getDriver() const; + void setDriver(const std::string& driver); + const std::string& getHardware() const; + void setHardware(const std::string& hardware); + + bool hasTimestamps() const; + void setTimestamps(bool timestamps); + + const std::vector& getChannels() const; + + std::string getDeviceArgs(); private: - std::string name; - std::string serial; - std::string product; - std::string manufacturer; - std::string tuner; - bool available; + int index; + std::string name, serial, product, manufacturer, tuner; + std::string driver, hardware; + bool timestamps, available; + + std::vector channels; }; diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 7e76654..8168df7 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -96,16 +96,22 @@ void SDRPostThread::run() { fpData.resize(dataSize); dataOut.resize(dataSize); } - - if (swapIQ) { - for (int i = 0; i < dataSize; i++) { - fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])]; - } - } else { - for (int i = 0; i < dataSize; i++) { - fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])]; - } + + + for (int i = 0; i < dataSize; i++) { + fpData[i].real = data_in->data[i*2]; + fpData[i].imag = data_in->data[i*2+1]; } + +// if (swapIQ) { +// for (int i = 0; i < dataSize; i++) { +// fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])]; +// } +// } else { +// for (int i = 0; i < dataSize; i++) { +// fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])]; +// } +// } iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]); diff --git a/src/sdr/SDRPostThread.h b/src/sdr/SDRPostThread.h index 0162e7e..6137df3 100644 --- a/src/sdr/SDRPostThread.h +++ b/src/sdr/SDRPostThread.h @@ -1,6 +1,10 @@ #pragma once +#if USE_RTL_SDR #include "SDRThread.h" +#else +#include "SoapySDRThread.h" +#endif #include class SDRPostThread : public IOThread { diff --git a/src/sdr/SoapySDRThread.cpp b/src/sdr/SoapySDRThread.cpp new file mode 100644 index 0000000..ccd2653 --- /dev/null +++ b/src/sdr/SoapySDRThread.cpp @@ -0,0 +1,459 @@ +#include "SoapySDRThread.h" +#include "CubicSDRDefs.h" +#include +#include "CubicSDR.h" +#include + +#include +#include +#include +#include + +std::vector SDRThread::factories; +std::vector SDRThread::modules; +std::vector SDRThread::devs; + + +SDRThread::SDRThread() : IOThread() { + offset.store(0); + deviceId.store(-1); +// dev = NULL; + sampleRate.store(DEFAULT_SAMPLE_RATE); +} + +SDRThread::~SDRThread() { +// rtlsdr_close(dev); +} + + +std::vector *SDRThread::enumerate_devices() { + + if (SDRThread::devs.size()) { + return &SDRThread::devs; + } + + std::cout << "SoapySDR init.." << std::endl; + std::cout << "\tAPI Version: v" << SoapySDR::getAPIVersion() << std::endl; + std::cout << "\tABI Version: v" << SoapySDR::getABIVersion() << std::endl; + std::cout << "\tInstall root: " << SoapySDR::getRootPath() << std::endl; + + modules = SoapySDR::listModules(); + for (size_t i = 0; i < modules.size(); i++) { + std::cout << "\tModule found: " << modules[i] << std::endl; + } + if (modules.empty()) { + std::cout << "No modules found!" << std::endl; + } + + std::cout << "\tLoading modules... " << std::flush; + SoapySDR::loadModules(); + std::cout << "done" << std::endl; + + if (SDRThread::factories.size()) { + SDRThread::factories.erase(SDRThread::factories.begin(), SDRThread::factories.end()); + } + + std::cout << "\tAvailable factories..."; + SoapySDR::FindFunctions factories = SoapySDR::Registry::listFindFunctions(); + for (SoapySDR::FindFunctions::const_iterator it = factories.begin(); it != factories.end(); ++it) { + if (it != factories.begin()) { + std::cout << ", "; + } + std::cout << it->first; + SDRThread::factories.push_back(it->first); + } + if (factories.empty()) { + std::cout << "No factories found!" << std::endl; + } + std::cout << std::endl; + + + std::vector results = SoapySDR::Device::enumerate(); + std::map deviceIndexes; + + for (size_t i = 0; i < results.size(); i++) { + std::cout << "Found device " << i << std::endl; + SDRDeviceInfo *dev = new SDRDeviceInfo(); + for (SoapySDR::Kwargs::const_iterator it = results[i].begin(); it != results[i].end(); ++it) { + std::cout << " " << it->first << " = " << it->second << std::endl; + if (it->first == "driver") { + dev->setDriver(it->second); + } else if (it->first == "label") { + dev->setName(it->second); + } +// else if (it->first == dev->getDriver()) { +// dev->setIndex(std::stoi(it->second.c_str())); +// } + } + + dev->setIndex(deviceIndexes[dev->getDriver()]); + deviceIndexes[dev->getDriver()]++; + + std::cout << "Make device " << dev->getDeviceArgs() << std::endl; + try { + SoapySDR::Device *device = SoapySDR::Device::make(dev->getDeviceArgs()); + SoapySDR::Kwargs info = device->getHardwareInfo(); + for (SoapySDR::Kwargs::const_iterator it = info.begin(); it != info.end(); ++it) { + std::cout << " " << it->first << "=" << it->second << std::endl; + if (it->first == "hardware") { + dev->setHardware(it->second); + } + } + SoapySDR::Device::unmake(device); + dev->setAvailable(true); + } catch (const std::exception &ex) { + std::cerr << "Error making device: " << ex.what() << std::endl; + dev->setAvailable(false); + } + std::cout << std::endl; + + SDRThread::devs.push_back(dev); + } + if (results.empty()) { + std::cout << "No devices found!" << std::endl; + } + std::cout << std::endl; + + return &SDRThread::devs; +} + +void SDRThread::run() { +//#ifdef __APPLE__ +// pthread_t tID = pthread_self(); // ID of this thread +// int priority = sched_get_priority_max( SCHED_FIFO) - 1; +// sched_param prio = { priority }; // scheduling priority of thread +// pthread_setschedparam(tID, SCHED_FIFO, &prio); +//#endif + + std::cout << "SDR thread initializing.." << std::endl; + + if (deviceId == -1 && devs.size() == 0) { + std::cout << "No devices found.. SDR Thread exiting.." << std::endl; + return; + } else { + if (deviceId == -1) { + deviceId = 0; + } + std::cout << "Using device #" << deviceId << std::endl; + } + + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devs[deviceId]->getDeviceId()); + + long long frequency = wxGetApp().getConfig()->getCenterFreq(); + int ppm = devConfig->getPPM(); + int direct_sampling_mode = devConfig->getDirectSampling();; +// int buf_size = BUF_SIZE; + offset.store(devConfig->getOffset()); + wxGetApp().setSwapIQ(devConfig->getIQSwap()); + + + SDRDeviceInfo *dev = devs[deviceId]; + std::vector dev_results = SoapySDR::Device::enumerate(dev->getDeviceArgs()); + SoapySDR::Device *device = SoapySDR::Device::make(dev_results[dev->getIndex()]); + + device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); + device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); + device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); + device->setGainMode(SOAPY_SDR_RX,0, true); + + SoapySDR::Stream *stream = device->setupStream(SOAPY_SDR_RX,"CF32"); + device->activateStream(stream); + + void *buffs[1]; + + buffs[0] = malloc(BUF_SIZE * sizeof(float)); + + int flags; + long long timeNs; + + ReBuffer buffers; + + SDRThreadIQDataQueue* iqDataOutQueue = (SDRThreadIQDataQueue*) getOutputQueue("IQDataOutput"); + SDRThreadCommandQueue* cmdQueue = (SDRThreadCommandQueue*) getInputQueue("SDRCommandQueue"); + + while (!terminated) { + if (!cmdQueue->empty()) { + bool freq_changed = false; + bool offset_changed = false; + bool rate_changed = false; + bool device_changed = false; + bool ppm_changed = false; + bool direct_sampling_changed = false; + long long new_freq = frequency; + long long new_offset = offset.load(); + long long new_rate = sampleRate.load(); + int new_device = deviceId; + int new_ppm = ppm; + + while (!cmdQueue->empty()) { + SDRThreadCommand command; + cmdQueue->pop(command); + + switch (command.cmd) { + case SDRThreadCommand::SDR_THREAD_CMD_TUNE: + freq_changed = true; + new_freq = command.llong_value; + if (new_freq < sampleRate.load() / 2) { + new_freq = sampleRate.load() / 2; + } + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET: + offset_changed = true; + new_offset = command.llong_value; + std::cout << "Set offset: " << new_offset << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE: + rate_changed = true; + new_rate = command.llong_value; + std::cout << "Set sample rate: " << new_rate << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE: + device_changed = true; + new_device = (int) command.llong_value; + std::cout << "Set device: " << new_device << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_PPM: + ppm_changed = true; + new_ppm = (int) command.llong_value; + //std::cout << "Set PPM: " << new_ppm << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING: + direct_sampling_mode = (int)command.llong_value; + direct_sampling_changed = true; + break; + default: + break; + } + } + + if (device_changed) { + device->deactivateStream(stream); + device->closeStream(stream); + SoapySDR::Device::unmake(device); + + SDRDeviceInfo *dev = devs[new_device]; + std::vector dev_results = SoapySDR::Device::enumerate(dev->getDeviceArgs()); + device = SoapySDR::Device::make(dev_results[dev->getIndex()]); + + device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); + device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); + device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); + device->setGainMode(SOAPY_SDR_RX,0, true); + + SoapySDR::Stream *stream = device->setupStream(SOAPY_SDR_RX,"CF32"); + device->activateStream(stream); + } + + if (offset_changed) { + if (!freq_changed) { + new_freq = frequency; + freq_changed = true; + } + offset.store(new_offset); + } + if (rate_changed) { + device->setSampleRate(SOAPY_SDR_RX,0,new_rate); + sampleRate.store(device->getSampleRate(SOAPY_SDR_RX,0)); + } + if (freq_changed) { + frequency = new_freq; + device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load()); + } + if (ppm_changed) { + ppm = new_ppm; + device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm); + } + if (direct_sampling_changed) { +// rtlsdr_set_direct_sampling(dev, direct_sampling_mode); + } + } + + + int n_read = device->readStream(stream, buffs, BUF_SIZE/2, flags, timeNs, 99999999); + +// std::cout << n_read << ", " << timeNs << std::endl; + + SDRThreadIQData *dataOut = buffers.getBuffer(); + + dataOut->setRefCount(1); + dataOut->frequency = frequency; + dataOut->sampleRate = sampleRate.load(); + + dataOut->data.resize(n_read * 2); + memcpy(&dataOut->data[0],buffs[0],n_read * sizeof(float) * 2); + + if (iqDataOutQueue != NULL) { + iqDataOutQueue->push(dataOut); + } else { + dataOut->setRefCount(0); + } + + } + device->deactivateStream(stream); + device->closeStream(stream); + SoapySDR::Device::unmake(device); + +/* + + + rtlsdr_open(&dev, deviceId); + rtlsdr_set_sample_rate(dev, sampleRate.load()); + rtlsdr_set_center_freq(dev, frequency - offset.load()); + rtlsdr_set_freq_correction(dev, ppm); + rtlsdr_set_agc_mode(dev, 1); + rtlsdr_set_offset_tuning(dev, 0); + rtlsdr_reset_buffer(dev); + +// sampleRate = rtlsdr_get_sample_rate(dev); + + std::cout << "Sample Rate is: " << sampleRate.load() << std::endl; + + int n_read; + double seconds = 0.0; + + std::cout << "SDR thread started.." << std::endl; + + ReBuffer buffers; + + SDRThreadIQDataQueue* iqDataOutQueue = (SDRThreadIQDataQueue*) getOutputQueue("IQDataOutput"); + SDRThreadCommandQueue* cmdQueue = (SDRThreadCommandQueue*) getInputQueue("SDRCommandQueue"); + + while (!terminated) { + if (!cmdQueue->empty()) { + bool freq_changed = false; + bool offset_changed = false; + bool rate_changed = false; + bool device_changed = false; + bool ppm_changed = false; + bool direct_sampling_changed = false; + long long new_freq = frequency; + long long new_offset = offset.load(); + long long new_rate = sampleRate.load(); + int new_device = deviceId; + int new_ppm = ppm; + + while (!cmdQueue->empty()) { + SDRThreadCommand command; + cmdQueue->pop(command); + + switch (command.cmd) { + case SDRThreadCommand::SDR_THREAD_CMD_TUNE: + freq_changed = true; + new_freq = command.llong_value; + if (new_freq < sampleRate.load() / 2) { + new_freq = sampleRate.load() / 2; + } +// std::cout << "Set frequency: " << new_freq << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET: + offset_changed = true; + new_offset = command.llong_value; + std::cout << "Set offset: " << new_offset << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE: + rate_changed = true; + new_rate = command.llong_value; + if (new_rate <= 250000) { + buf_size = BUF_SIZE/4; + } else if (new_rate < 1500000) { + buf_size = BUF_SIZE/2; + } else { + buf_size = BUF_SIZE; + } + std::cout << "Set sample rate: " << new_rate << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE: + device_changed = true; + new_device = (int) command.llong_value; + std::cout << "Set device: " << new_device << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_PPM: + ppm_changed = true; + new_ppm = (int) command.llong_value; + //std::cout << "Set PPM: " << new_ppm << std::endl; + break; + case SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING: + direct_sampling_mode = (int)command.llong_value; + direct_sampling_changed = true; + break; + default: + break; + } + } + + if (device_changed) { + rtlsdr_close(dev); + rtlsdr_open(&dev, new_device); + rtlsdr_set_sample_rate(dev, sampleRate.load()); + rtlsdr_set_center_freq(dev, frequency - offset.load()); + rtlsdr_set_freq_correction(dev, ppm); + rtlsdr_set_agc_mode(dev, 1); + rtlsdr_set_offset_tuning(dev, 0); + rtlsdr_set_direct_sampling(dev, direct_sampling_mode); + rtlsdr_reset_buffer(dev); + } + if (offset_changed) { + if (!freq_changed) { + new_freq = frequency; + freq_changed = true; + } + offset.store(new_offset); + } + if (rate_changed) { + rtlsdr_set_sample_rate(dev, new_rate); + rtlsdr_reset_buffer(dev); + sampleRate.store(rtlsdr_get_sample_rate(dev)); + } + if (freq_changed) { + frequency = new_freq; + rtlsdr_set_center_freq(dev, frequency - offset.load()); + } + if (ppm_changed) { + ppm = new_ppm; + rtlsdr_set_freq_correction(dev, ppm); + } + if (direct_sampling_changed) { + rtlsdr_set_direct_sampling(dev, direct_sampling_mode); + } + } + + rtlsdr_read_sync(dev, buf, buf_size, &n_read); + + SDRThreadIQData *dataOut = buffers.getBuffer(); + +// std::lock_guard < std::mutex > lock(dataOut->m_mutex); + dataOut->setRefCount(1); + dataOut->frequency = frequency; + dataOut->sampleRate = sampleRate.load(); + + if (dataOut->data.capacity() < n_read) { + dataOut->data.reserve(n_read); + } + + if (dataOut->data.size() != n_read) { + dataOut->data.resize(n_read); + } + + memcpy(&dataOut->data[0], buf, n_read); + + double time_slice = (double) n_read / (double) sampleRate.load(); + seconds += time_slice; + + if (iqDataOutQueue != NULL) { + iqDataOutQueue->push(dataOut); + } + } + +// buffers.purge(); + */ + std::cout << "SDR thread done." << std::endl; +} + + +int SDRThread::getDeviceId() const { + return deviceId.load(); +} + +void SDRThread::setDeviceId(int deviceId) { + this->deviceId.store(deviceId); +} diff --git a/src/sdr/SoapySDRThread.h b/src/sdr/SoapySDRThread.h new file mode 100644 index 0000000..a4b9311 --- /dev/null +++ b/src/sdr/SoapySDRThread.h @@ -0,0 +1,73 @@ +#pragma once + +#include + +#include "ThreadQueue.h" +#include "DemodulatorMgr.h" +#include "SDRDeviceInfo.h" + +class SDRThreadCommand { +public: + enum SDRThreadCommandEnum { + SDR_THREAD_CMD_NULL, SDR_THREAD_CMD_TUNE, SDR_THREAD_CMD_SET_OFFSET, SDR_THREAD_CMD_SET_SAMPLERATE, SDR_THREAD_CMD_SET_PPM, SDR_THREAD_CMD_SET_DEVICE, SDR_THREAD_CMD_SET_DIRECT_SAMPLING + }; + + SDRThreadCommand() : + cmd(SDR_THREAD_CMD_NULL), llong_value(0) { + + } + + SDRThreadCommand(SDRThreadCommandEnum cmd) : + cmd(cmd), llong_value(0) { + + } + + SDRThreadCommandEnum cmd; + long long llong_value; +}; + +class SDRThreadIQData: public ReferenceCounter { +public: + long long frequency; + long long sampleRate; +// std::vector data; + std::vector data; + + SDRThreadIQData() : + frequency(0), sampleRate(DEFAULT_SAMPLE_RATE) { + + } + + SDRThreadIQData(long long bandwidth, long long frequency, std::vector *data) : + frequency(frequency), sampleRate(bandwidth) { + + } + + ~SDRThreadIQData() { + + } +}; + +typedef ThreadQueue SDRThreadCommandQueue; +typedef ThreadQueue SDRThreadIQDataQueue; + +class SDRThread : public IOThread { +public: + SDRThread(); + ~SDRThread(); + + static std::vector *enumerate_devices(); + + void run(); + + int getDeviceId() const; + void setDeviceId(int deviceId); + +protected: + static std::vector factories; + static std::vector modules; + static std::vector devs; + std::atomic sampleRate; + std::atomic_llong offset; + std::atomic_int deviceId; +};