pax_global_header00006660000000000000000000000064140037221170014507gustar00rootroot0000000000000052 comment=e4b963926012399904aceb57690df3a4f293ce67 SoapyRTLSDR-soapy-rtl-sdr-0.3.2/000077500000000000000000000000001400372211700162555ustar00rootroot00000000000000SoapyRTLSDR-soapy-rtl-sdr-0.3.2/.gitignore000066400000000000000000000000061400372211700202410ustar00rootroot00000000000000build SoapyRTLSDR-soapy-rtl-sdr-0.3.2/.travis.yml000066400000000000000000000030501400372211700203640ustar00rootroot00000000000000######################################################################## ## Travis CI config for SoapyRTLSDR ## ## * installs rtl-sdr from PPA ## * installs SoapySDR from source ## * confirms build and install ## * checks that drivers load ######################################################################## sudo: required dist: trusty language: cpp compiler: gcc env: global: - INSTALL_PREFIX=/usr/local - SOAPY_SDR_BRANCH=master matrix: - BUILD_TYPE=Debug - BUILD_TYPE=Release before_install: # regular ubuntu packages - sudo add-apt-repository main - sudo add-apt-repository universe # driver development files from ppa - sudo add-apt-repository -y ppa:myriadrf/drivers # update after package changes - sudo apt-get update install: #sdr development files - sudo apt-get install --no-install-recommends -q -y librtlsdr-dev # install SoapySDR from source - git clone https://github.com/pothosware/SoapySDR.git - pushd SoapySDR - git checkout ${SOAPY_SDR_BRANCH} - mkdir build && cd build - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_PYTHON=OFF -DENABLE_PYTHON3=OFF - make && sudo make install - popd script: - mkdir build && cd build - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} - make && sudo make install # print info about the install - export LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH} - export PATH=${INSTALL_PREFIX}/bin:${PATH} - SoapySDRUtil --info - SoapySDRUtil --check=rtlsdr SoapyRTLSDR-soapy-rtl-sdr-0.3.2/CMakeLists.txt000066400000000000000000000043451400372211700210230ustar00rootroot00000000000000######################################################################## # Build Soapy SDR support module for RTL-SDR Devices ######################################################################## cmake_minimum_required(VERSION 2.8.7) project(SoapyRTLSDR CXX) find_package(SoapySDR "0.4.0" NO_MODULE REQUIRED) if (NOT SoapySDR_FOUND) message(FATAL_ERROR "Soapy SDR development files not found...") endif () list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) find_package(RTLSDR) if (NOT RTLSDR_FOUND) message(FATAL_ERROR "RTL-SDR development files not found...") endif () message(STATUS "RTLSDR_INCLUDE_DIRS - ${RTLSDR_INCLUDE_DIRS}") message(STATUS "RTLSDR_LIBRARIES - ${RTLSDR_LIBRARIES}") include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${RTLSDR_INCLUDE_DIRS}) # Test for Atomics include(CheckAtomic) if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB OR NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) set(ATOMIC_LIBS "atomic") endif() #enable c++11 features if(CMAKE_COMPILER_IS_GNUCXX) #C++11 is a required language feature for this project include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_STD_CXX11) if(HAS_STD_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else(HAS_STD_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") endif() #Thread support enabled (not the same as -lpthread) list(APPEND RTLSDR_LIBRARIES -pthread) #disable warnings for unused parameters add_definitions(-Wno-unused-parameter) endif(CMAKE_COMPILER_IS_GNUCXX) if (APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wc++11-extensions") endif(APPLE) # check if rtlsdr library includes support for bias-tee include(CheckFunctionExists) set(CMAKE_REQUIRED_LIBRARIES ${RTLSDR_LIBRARIES}) check_function_exists(rtlsdr_set_bias_tee HAS_RTLSDR_SET_BIAS_TEE) unset(CMAKE_REQUIRED_LIBRARIES) if (HAS_RTLSDR_SET_BIAS_TEE) add_definitions(-DHAS_RTLSDR_SET_BIAS_TEE) endif() set(OTHER_LIBS "" CACHE STRING "Other libraries") SOAPY_SDR_MODULE_UTIL( TARGET rtlsdrSupport SOURCES SoapyRTLSDR.hpp Registration.cpp Settings.cpp Streaming.cpp LIBRARIES ${RTLSDR_LIBRARIES} ${ATOMIC_LIBS} ${OTHER_LIBS} ) SoapyRTLSDR-soapy-rtl-sdr-0.3.2/Changelog.txt000066400000000000000000000037351400372211700207150ustar00rootroot00000000000000Release 0.3.2 (2021-01-25) ========================== - Revert pull request #49, freq can be set while stream active - Fix setFrequencyCorrection exceptional return code - Fix to read back after setting sampleRate, ppm, and centerFrequency; or throw on invalid input - Fix rtlsdr_get_tuner_gain() in setupStream() (closes #51) Release 0.3.1 (2020-07-20) ========================== - Refactor and fix open by serial implementation - Support recent rtlsdr_set_bias_tee() API - Do not advertise full duplex capability - Possible fix for issue with misaligned center frequency - Implement hardware time API using absolute sample count Release 0.3.0 (2018-12-07) ========================== - digital AGC now available through "digital_agc" setting - gain mode now affects rtlsdr_set_tuner_gain_mode() - getHardwareKey() returns the actual tuner type Release 0.2.5 (2018-05-05) ========================== - Deactivate the stream thread in closeStream() - Fix clipping for the int8 conversion support Release 0.2.4 (2017-06-15) ========================== - readStream - also drop remainder buffer on reset - Fixed configuration input for num async buffers Release 0.2.3 (2017-04-29) ========================== - Added support for frequency correction API - Separate buffer count for ring buffer and usb - Larger buffer size - same as rtl defaults - Use atomics for ring buffer implementation - Use Format string constants for stream types Release 0.2.2 (2016-09-01) ========================== - Update debian files for SoapySDR module ABI format - Fix build failure on all big endian architectures Release 0.2.1 (2016-04-25) ========================== - Fixes for E4000 and FC001x tuner types - Fixed debian control file Maintainer/Uploaders Release 0.2.0 (2015-12-10) ========================== - Added device info arguments and device settings - Added support for the direct access buffer API Release 0.1.0 (2015-10-10) ========================== - Initial release of Soapy RTL-SDR support module SoapyRTLSDR-soapy-rtl-sdr-0.3.2/CheckAtomic.cmake000066400000000000000000000052601400372211700214340ustar00rootroot00000000000000# - Try to find if atomics need -latomic linking # Once done this will define # HAVE_CXX_ATOMICS_WITHOUT_LIB - Wether atomic types work without -latomic # HAVE_CXX_ATOMICS64_WITHOUT_LIB - Wether 64 bit atomic types work without -latomic INCLUDE(CheckCXXSourceCompiles) INCLUDE(CheckLibraryExists) # Sometimes linking against libatomic is required for atomic ops, if # the platform doesn't support lock-free atomics. function(check_working_cxx_atomics varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") CHECK_CXX_SOURCE_COMPILES(" #include std::atomic x; int main() { return std::atomic_is_lock_free(&x); } " ${varname}) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) endfunction(check_working_cxx_atomics) function(check_working_cxx_atomics64 varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") CHECK_CXX_SOURCE_COMPILES(" #include #include std::atomic x (0); int main() { uint64_t i = x.load(std::memory_order_relaxed); return std::atomic_is_lock_free(&x); } " ${varname}) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) endfunction(check_working_cxx_atomics64) # Check for atomic operations. if(MSVC) # This isn't necessary on MSVC. set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) else() # First check if atomics work without the library. check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) endif() # If not, check if the library exists, and atomics work with it. if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) if(NOT HAVE_LIBATOMIC) message(STATUS "Host compiler appears to require libatomic, but cannot locate it.") endif() list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) if (NOT HAVE_CXX_ATOMICS_WITH_LIB) message(FATAL_ERROR "Host compiler must support std::atomic!") endif() endif() # Check for 64 bit atomic operations. if(MSVC) set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) else() check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) endif() # If not, check if the library exists, and atomics work with it. if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) check_library_exists(atomic __atomic_load_8 "" HAVE_LIBATOMIC64) if(NOT HAVE_LIBATOMIC64) message(STATUS "Host compiler appears to require libatomic, but cannot locate it.") endif() list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) message(FATAL_ERROR "Host compiler must support std::atomic!") endif() endif() SoapyRTLSDR-soapy-rtl-sdr-0.3.2/FindRTLSDR.cmake000066400000000000000000000043321400372211700210740ustar00rootroot00000000000000# # Copyright 2012-2013 The Iris Project Developers. See the # COPYRIGHT file at the top-level directory of this distribution # and at http://www.softwareradiosystems.com/iris/copyright.html. # # This file is part of the Iris Project. # # Iris is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # Iris 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 Lesser General Public License for more details. # # A copy of the GNU Lesser General Public License can be found in # the LICENSE file in the top-level directory of this distribution # and at http://www.gnu.org/licenses/. # # - Try to find rtlsdr - the hardware driver for the realtek chip in the dvb receivers # Once done this will define # RTLSDR_FOUND - System has rtlsdr # RTLSDR_LIBRARIES - The rtlsdr libraries # RTLSDR_INCLUDE_DIRS - The rtlsdr include directories # RTLSDR_LIB_DIRS - The rtlsdr library directories if(NOT RTLSDR_FOUND) find_package(PkgConfig) pkg_check_modules (RTLSDR_PKG librtlsdr) set(RTLSDR_DEFINITIONS ${PC_RTLSDR_CFLAGS_OTHER}) find_path(RTLSDR_INCLUDE_DIR NAMES rtl-sdr.h HINTS ${RTLSDR_PKG_INCLUDE_DIRS} $ENV{RTLSDR_DIR}/include PATHS /usr/local/include /usr/include /opt/include /opt/local/include) find_library(RTLSDR_LIBRARY NAMES rtlsdr HINTS ${RTLSDR_PKG_LIBRARY_DIRS} $ENV{RTLSDR_DIR}/include PATHS /usr/local/lib /usr/lib /opt/lib /opt/local/lib) set(RTLSDR_LIBRARIES ${RTLSDR_LIBRARY} ) set(RTLSDR_INCLUDE_DIRS ${RTLSDR_INCLUDE_DIR} ) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LibRTLSDR_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(RTLSDR DEFAULT_MSG RTLSDR_LIBRARY RTLSDR_INCLUDE_DIR) mark_as_advanced(RTLSDR_INCLUDE_DIR RTLSDR_LIBRARY) endif(NOT RTLSDR_FOUND) SoapyRTLSDR-soapy-rtl-sdr-0.3.2/LICENSE.txt000066400000000000000000000020731400372211700201020ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Charles J. Cliffe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.SoapyRTLSDR-soapy-rtl-sdr-0.3.2/README.md000066400000000000000000000027401400372211700175370ustar00rootroot00000000000000# Soapy SDR module for RTL-SDR ## Build Status - Travis: [![Travis Build Status](https://travis-ci.org/pothosware/SoapyRTLSDR.svg?branch=master)](https://travis-ci.org/pothosware/SoapyRTLSDR) ## Dependencies * SoapySDR - https://github.com/pothosware/SoapySDR/wiki * librtl-sdr - http://sdr.osmocom.org/trac/wiki/rtl-sdr ## Documentation * https://github.com/pothosware/SoapyRTLSDR/wiki ## Licensing information The MIT License (MIT) Copyright (c) 2015 Charles J. Cliffe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SoapyRTLSDR-soapy-rtl-sdr-0.3.2/Registration.cpp000066400000000000000000000065231400372211700214410ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Charles J. Cliffe * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyRTLSDR.hpp" #include #include #include //lookup the tuner by opening the device, it's used in the discovery arguments //the tuner is cached because the device cannot be opened twice in the same process, //and we require that findRTLSDR() yield the same results for SoapySDR device cache. //if another process attempts to find an open rtlsdr, it will be marked unavailable static std::string get_tuner(const std::string &serial, const size_t deviceIndex) { static std::mutex mutex; std::lock_guard lock(mutex); static std::map cache; auto it = cache.find(serial); if (it != cache.end()) return it->second; rtlsdr_dev_t *devTest; if (rtlsdr_open(&devTest, deviceIndex) != 0) return "unavailable"; const auto tuner = SoapyRTLSDR::rtlTunerToString(rtlsdr_get_tuner_type(devTest)); rtlsdr_close(devTest); cache[serial] = tuner; return tuner; } static std::vector findRTLSDR(const SoapySDR::Kwargs &args) { std::vector results; char manufact[256], product[256], serial[256]; const size_t this_count = rtlsdr_get_device_count(); for (size_t i = 0; i < this_count; i++) { if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) != 0) { SoapySDR_logf(SOAPY_SDR_ERROR, "rtlsdr_get_device_usb_strings(%zu) failed", i); continue; } SoapySDR_logf(SOAPY_SDR_DEBUG, "\tManufacturer: %s, Product Name: %s, Serial: %s", manufact, product, serial); SoapySDR::Kwargs devInfo; devInfo["label"] = std::string(rtlsdr_get_device_name(i)) + " :: " + serial; devInfo["product"] = product; devInfo["serial"] = serial; devInfo["manufacturer"] = manufact; devInfo["tuner"] = get_tuner(serial, i); //filtering by serial if (args.count("serial") != 0 and args.at("serial") != serial) continue; results.push_back(devInfo); } return results; } static SoapySDR::Device *makeRTLSDR(const SoapySDR::Kwargs &args) { return new SoapyRTLSDR(args); } static SoapySDR::Registry registerRTLSDR("rtlsdr", &findRTLSDR, &makeRTLSDR, SOAPY_SDR_ABI_VERSION); SoapyRTLSDR-soapy-rtl-sdr-0.3.2/Settings.cpp000066400000000000000000000545241400372211700205730ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Charles J. Cliffe * Copyright (c) 2015-2017 Josh Blum * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyRTLSDR.hpp" #include #include SoapyRTLSDR::SoapyRTLSDR(const SoapySDR::Kwargs &args): deviceId(-1), dev(nullptr), rxFormat(RTL_RX_FORMAT_FLOAT32), tunerType(RTLSDR_TUNER_R820T), sampleRate(2048000), centerFrequency(100000000), bandwidth(0), ppm(0), directSamplingMode(0), numBuffers(DEFAULT_NUM_BUFFERS), bufferLength(DEFAULT_BUFFER_LENGTH), iqSwap(false), gainMode(false), offsetMode(false), digitalAGC(false), #if HAS_RTLSDR_SET_BIAS_TEE biasTee(false), #endif ticks(false), bufferedElems(0), resetBuffer(false), gainMin(0.0), gainMax(0.0) { if (args.count("label") != 0) SoapySDR_logf(SOAPY_SDR_INFO, "Opening %s...", args.at("label").c_str()); //if a serial is not present, then findRTLSDR had zero devices enumerated if (args.count("serial") == 0) throw std::runtime_error("No RTL-SDR devices found!"); const auto serial = args.at("serial"); deviceId = rtlsdr_get_index_by_serial(serial.c_str()); if (deviceId < 0) throw std::runtime_error("rtlsdr_get_index_by_serial("+serial+") - " + std::to_string(deviceId)); if (args.count("tuner") != 0) tunerType = rtlStringToTuner(args.at("tuner")); SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Tuner type: %s", rtlTunerToString(tunerType).c_str()); SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR opening device %d", deviceId); if (rtlsdr_open(&dev, deviceId) != 0) { throw std::runtime_error("Unable to open RTL-SDR device"); } //extract min/max overall gain range int num_gains = rtlsdr_get_tuner_gains(dev, nullptr); if (num_gains > 0) { std::vector gains(num_gains); rtlsdr_get_tuner_gains(dev, gains.data()); gainMin = *std::min_element(gains.begin(), gains.end()) / 10.0; gainMax = *std::max_element(gains.begin(), gains.end()) / 10.0; } } SoapyRTLSDR::~SoapyRTLSDR(void) { //cleanup device handles rtlsdr_close(dev); } /******************************************************************* * Identification API ******************************************************************/ std::string SoapyRTLSDR::getDriverKey(void) const { return "RTLSDR"; } std::string SoapyRTLSDR::getHardwareKey(void) const { switch (rtlsdr_get_tuner_type(dev)) { case RTLSDR_TUNER_UNKNOWN: return "UNKNOWN"; case RTLSDR_TUNER_E4000: return "E4000"; case RTLSDR_TUNER_FC0012: return "FC0012"; case RTLSDR_TUNER_FC0013: return "FC0013"; case RTLSDR_TUNER_FC2580: return "FC2580"; case RTLSDR_TUNER_R820T: return "R820T"; case RTLSDR_TUNER_R828D: return "R828D"; default: return "OTHER"; } } SoapySDR::Kwargs SoapyRTLSDR::getHardwareInfo(void) const { //key/value pairs for any useful information //this also gets printed in --probe SoapySDR::Kwargs args; args["origin"] = "https://github.com/pothosware/SoapyRTLSDR"; args["index"] = std::to_string(deviceId); return args; } /******************************************************************* * Channels API ******************************************************************/ size_t SoapyRTLSDR::getNumChannels(const int dir) const { return (dir == SOAPY_SDR_RX) ? 1 : 0; } bool SoapyRTLSDR::getFullDuplex(const int direction, const size_t channel) const { return false; } /******************************************************************* * Antenna API ******************************************************************/ std::vector SoapyRTLSDR::listAntennas(const int direction, const size_t channel) const { std::vector antennas; antennas.push_back("RX"); return antennas; } void SoapyRTLSDR::setAntenna(const int direction, const size_t channel, const std::string &name) { if (direction != SOAPY_SDR_RX) { throw std::runtime_error("setAntena failed: RTL-SDR only supports RX"); } } std::string SoapyRTLSDR::getAntenna(const int direction, const size_t channel) const { return "RX"; } /******************************************************************* * Frontend corrections API ******************************************************************/ bool SoapyRTLSDR::hasDCOffsetMode(const int direction, const size_t channel) const { return false; } bool SoapyRTLSDR::hasFrequencyCorrection(const int direction, const size_t channel) const { return true; } void SoapyRTLSDR::setFrequencyCorrection(const int direction, const size_t channel, const double value) { int r = rtlsdr_set_freq_correction(dev, int(value)); if (r == -2) { return; // CORR didn't actually change, we are done } if (r != 0) { throw std::runtime_error("setFrequencyCorrection failed"); } ppm = rtlsdr_get_freq_correction(dev); } double SoapyRTLSDR::getFrequencyCorrection(const int direction, const size_t channel) const { return double(ppm); } /******************************************************************* * Gain API ******************************************************************/ std::vector SoapyRTLSDR::listGains(const int direction, const size_t channel) const { //list available gain elements, //the functions below have a "name" parameter std::vector results; if (tunerType == RTLSDR_TUNER_E4000) { results.push_back("IF1"); results.push_back("IF2"); results.push_back("IF3"); results.push_back("IF4"); results.push_back("IF5"); results.push_back("IF6"); } results.push_back("TUNER"); return results; } bool SoapyRTLSDR::hasGainMode(const int direction, const size_t channel) const { return true; } void SoapyRTLSDR::setGainMode(const int direction, const size_t channel, const bool automatic) { gainMode = automatic; SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting RTL-SDR gain mode: %s", automatic ? "Automatic" : "Manual"); rtlsdr_set_tuner_gain_mode(dev, gainMode ? 0 : 1); } bool SoapyRTLSDR::getGainMode(const int direction, const size_t channel) const { return gainMode; } void SoapyRTLSDR::setGain(const int direction, const size_t channel, const double value) { //set the overall gain by distributing it across available gain elements //OR delete this function to use SoapySDR's default gain distribution algorithm... SoapySDR::Device::setGain(direction, channel, value); } void SoapyRTLSDR::setGain(const int direction, const size_t channel, const std::string &name, const double value) { if ((name.length() >= 2) && (name.substr(0, 2) == "IF")) { int stage = 1; if (name.length() > 2) { int stage_in = name.at(2) - '0'; if ((stage_in < 1) || (stage_in > 6)) { throw std::runtime_error("Invalid IF stage, 1 or 1-6 for E4000"); } } if (tunerType == RTLSDR_TUNER_E4000) { IFGain[stage - 1] = getE4000Gain(stage, (int)value); } else { IFGain[stage - 1] = value; } SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting RTL-SDR IF Gain for stage %d: %f", stage, IFGain[stage - 1]); rtlsdr_set_tuner_if_gain(dev, stage, (int) IFGain[stage - 1] * 10.0); } if (name == "TUNER") { tunerGain = value; SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting RTL-SDR Tuner Gain: %f", tunerGain); rtlsdr_set_tuner_gain(dev, (int) tunerGain * 10.0); } } double SoapyRTLSDR::getGain(const int direction, const size_t channel, const std::string &name) const { if ((name.length() >= 2) && (name.substr(0, 2) == "IF")) { int stage = 1; if (name.length() > 2) { int stage_in = name.at(2) - '0'; if ((stage_in < 1) || (stage_in > 6)) { throw std::runtime_error("Invalid IF stage, 1 or 1-6 for E4000"); } else { stage = stage_in; } } if (tunerType == RTLSDR_TUNER_E4000) { return getE4000Gain(stage, IFGain[stage - 1]); } return IFGain[stage - 1]; } if (name == "TUNER") { return tunerGain; } return 0; } SoapySDR::Range SoapyRTLSDR::getGainRange(const int direction, const size_t channel, const std::string &name) const { if (tunerType == RTLSDR_TUNER_E4000 && name != "TUNER") { if (name == "IF1") { return SoapySDR::Range(-3, 6); } if (name == "IF2" || name == "IF3") { return SoapySDR::Range(0, 9); } if (name == "IF4") { return SoapySDR::Range(0, 2); } if (name == "IF5" || name == "IF6") { return SoapySDR::Range(3, 15); } return SoapySDR::Range(gainMin, gainMax); } else { return SoapySDR::Range(gainMin, gainMax); } } /******************************************************************* * Frequency API ******************************************************************/ void SoapyRTLSDR::setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args) { if (name == "RF") { SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting center freq: %d", (uint32_t)frequency); int r = rtlsdr_set_center_freq(dev, (uint32_t)frequency); if (r != 0) { throw std::runtime_error("setFrequency failed"); } centerFrequency = rtlsdr_get_center_freq(dev); } if (name == "CORR") { int r = rtlsdr_set_freq_correction(dev, (int)frequency); if (r == -2) { return; // CORR didn't actually change, we are done } if (r != 0) { throw std::runtime_error("setFrequencyCorrection failed"); } ppm = rtlsdr_get_freq_correction(dev); } } double SoapyRTLSDR::getFrequency(const int direction, const size_t channel, const std::string &name) const { if (name == "RF") { return (double) centerFrequency; } if (name == "CORR") { return (double) ppm; } return 0; } std::vector SoapyRTLSDR::listFrequencies(const int direction, const size_t channel) const { std::vector names; names.push_back("RF"); names.push_back("CORR"); return names; } SoapySDR::RangeList SoapyRTLSDR::getFrequencyRange( const int direction, const size_t channel, const std::string &name) const { SoapySDR::RangeList results; if (name == "RF") { if (tunerType == RTLSDR_TUNER_E4000) { results.push_back(SoapySDR::Range(52000000, 2200000000)); } else if (tunerType == RTLSDR_TUNER_FC0012) { results.push_back(SoapySDR::Range(22000000, 1100000000)); } else if (tunerType == RTLSDR_TUNER_FC0013) { results.push_back(SoapySDR::Range(22000000, 948600000)); } else { results.push_back(SoapySDR::Range(24000000, 1764000000)); } } if (name == "CORR") { results.push_back(SoapySDR::Range(-1000, 1000)); } return results; } SoapySDR::ArgInfoList SoapyRTLSDR::getFrequencyArgsInfo(const int direction, const size_t channel) const { SoapySDR::ArgInfoList freqArgs; // TODO: frequency arguments return freqArgs; } /******************************************************************* * Sample Rate API ******************************************************************/ void SoapyRTLSDR::setSampleRate(const int direction, const size_t channel, const double rate) { long long ns = SoapySDR::ticksToTimeNs(ticks, sampleRate); sampleRate = rate; resetBuffer = true; SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting sample rate: %d", sampleRate); int r = rtlsdr_set_sample_rate(dev, sampleRate); if (r == -EINVAL) { throw std::runtime_error("setSampleRate failed: RTL-SDR does not support this sample rate"); } if (r != 0) { throw std::runtime_error("setSampleRate failed"); } sampleRate = rtlsdr_get_sample_rate(dev); ticks = SoapySDR::timeNsToTicks(ns, sampleRate); } double SoapyRTLSDR::getSampleRate(const int direction, const size_t channel) const { return sampleRate; } std::vector SoapyRTLSDR::listSampleRates(const int direction, const size_t channel) const { std::vector results; results.push_back(250000); results.push_back(1024000); results.push_back(1536000); results.push_back(1792000); results.push_back(1920000); results.push_back(2048000); results.push_back(2160000); results.push_back(2560000); results.push_back(2880000); results.push_back(3200000); return results; } void SoapyRTLSDR::setBandwidth(const int direction, const size_t channel, const double bw) { int r = rtlsdr_set_tuner_bandwidth(dev, bw); if (r != 0) { throw std::runtime_error("setBandwidth failed"); } bandwidth = bw; } double SoapyRTLSDR::getBandwidth(const int direction, const size_t channel) const { if (bandwidth == 0) // auto / full bandwidth return sampleRate; return bandwidth; } std::vector SoapyRTLSDR::listBandwidths(const int direction, const size_t channel) const { std::vector results; return results; } SoapySDR::RangeList SoapyRTLSDR::getBandwidthRange(const int direction, const size_t channel) const { SoapySDR::RangeList results; // stub, not sure what the sensible ranges for different tuners are. results.push_back(SoapySDR::Range(0, 8000000)); return results; } /******************************************************************* * Time API ******************************************************************/ std::vector SoapyRTLSDR::listTimeSources(void) const { std::vector results; results.push_back("sw_ticks"); return results; } std::string SoapyRTLSDR::getTimeSource(void) const { return "sw_ticks"; } bool SoapyRTLSDR::hasHardwareTime(const std::string &what) const { return what == "" || what == "sw_ticks"; } long long SoapyRTLSDR::getHardwareTime(const std::string &what) const { return SoapySDR::ticksToTimeNs(ticks, sampleRate); } void SoapyRTLSDR::setHardwareTime(const long long timeNs, const std::string &what) { ticks = SoapySDR::timeNsToTicks(timeNs, sampleRate); } /******************************************************************* * Settings API ******************************************************************/ SoapySDR::ArgInfoList SoapyRTLSDR::getSettingInfo(void) const { SoapySDR::ArgInfoList setArgs; SoapySDR::ArgInfo directSampArg; directSampArg.key = "direct_samp"; directSampArg.value = "0"; directSampArg.name = "Direct Sampling"; directSampArg.description = "RTL-SDR Direct Sampling Mode"; directSampArg.type = SoapySDR::ArgInfo::STRING; directSampArg.options.push_back("0"); directSampArg.optionNames.push_back("Off"); directSampArg.options.push_back("1"); directSampArg.optionNames.push_back("I-ADC"); directSampArg.options.push_back("2"); directSampArg.optionNames.push_back("Q-ADC"); setArgs.push_back(directSampArg); SoapySDR::ArgInfo offsetTuneArg; offsetTuneArg.key = "offset_tune"; offsetTuneArg.value = "false"; offsetTuneArg.name = "Offset Tune"; offsetTuneArg.description = "RTL-SDR Offset Tuning Mode"; offsetTuneArg.type = SoapySDR::ArgInfo::BOOL; setArgs.push_back(offsetTuneArg); SoapySDR::ArgInfo iqSwapArg; iqSwapArg.key = "iq_swap"; iqSwapArg.value = "false"; iqSwapArg.name = "I/Q Swap"; iqSwapArg.description = "RTL-SDR I/Q Swap Mode"; iqSwapArg.type = SoapySDR::ArgInfo::BOOL; setArgs.push_back(iqSwapArg); SoapySDR::ArgInfo digitalAGCArg; digitalAGCArg.key = "digital_agc"; digitalAGCArg.value = "false"; digitalAGCArg.name = "Digital AGC"; digitalAGCArg.description = "RTL-SDR digital AGC Mode"; digitalAGCArg.type = SoapySDR::ArgInfo::BOOL; setArgs.push_back(digitalAGCArg); #if HAS_RTLSDR_SET_BIAS_TEE SoapySDR::ArgInfo biasTeeArg; biasTeeArg.key = "biastee"; biasTeeArg.value = "false"; biasTeeArg.name = "Bias Tee"; biasTeeArg.description = "RTL-SDR Blog V.3 Bias-Tee Mode"; biasTeeArg.type = SoapySDR::ArgInfo::BOOL; setArgs.push_back(biasTeeArg); #endif SoapySDR_logf(SOAPY_SDR_DEBUG, "SETARGS?"); return setArgs; } void SoapyRTLSDR::writeSetting(const std::string &key, const std::string &value) { if (key == "direct_samp") { try { directSamplingMode = std::stoi(value); } catch (const std::invalid_argument &) { SoapySDR_logf(SOAPY_SDR_ERROR, "RTL-SDR invalid direct sampling mode '%s', [0:Off, 1:I-ADC, 2:Q-ADC]", value.c_str()); directSamplingMode = 0; } SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR direct sampling mode: %d", directSamplingMode); rtlsdr_set_direct_sampling(dev, directSamplingMode); } else if (key == "iq_swap") { iqSwap = ((value=="true") ? true : false); SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR I/Q swap: %s", iqSwap ? "true" : "false"); } else if (key == "offset_tune") { offsetMode = (value == "true") ? true : false; SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR offset_tune mode: %s", offsetMode ? "true" : "false"); rtlsdr_set_offset_tuning(dev, offsetMode ? 1 : 0); } else if (key == "digital_agc") { digitalAGC = (value == "true") ? true : false; SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR digital agc mode: %s", digitalAGC ? "true" : "false"); rtlsdr_set_agc_mode(dev, digitalAGC ? 1 : 0); } #if HAS_RTLSDR_SET_BIAS_TEE else if (key == "biastee") { biasTee = (value == "true") ? true: false; SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR bias tee mode: %s", biasTee ? "true" : "false"); rtlsdr_set_bias_tee(dev, biasTee ? 1 : 0); } #endif } std::string SoapyRTLSDR::readSetting(const std::string &key) const { if (key == "direct_samp") { return std::to_string(directSamplingMode); } else if (key == "iq_swap") { return iqSwap?"true":"false"; } else if (key == "offset_tune") { return offsetMode?"true":"false"; } else if (key == "digital_agc") { return digitalAGC?"true":"false"; #if HAS_RTLSDR_SET_BIAS_TEE } else if (key == "biastee") { return biasTee?"true":"false"; #endif } SoapySDR_logf(SOAPY_SDR_WARNING, "Unknown setting '%s'", key.c_str()); return ""; } std::string SoapyRTLSDR::rtlTunerToString(rtlsdr_tuner tunerType) { std::string deviceTuner; switch (tunerType) { case RTLSDR_TUNER_UNKNOWN: deviceTuner = "Unknown"; break; case RTLSDR_TUNER_E4000: deviceTuner = "Elonics E4000"; break; case RTLSDR_TUNER_FC0012: deviceTuner = "Fitipower FC0012"; break; case RTLSDR_TUNER_FC0013: deviceTuner = "Fitipower FC0013"; break; case RTLSDR_TUNER_FC2580: deviceTuner = "Fitipower FC2580"; break; case RTLSDR_TUNER_R820T: deviceTuner = "Rafael Micro R820T"; break; case RTLSDR_TUNER_R828D: deviceTuner = "Rafael Micro R828D"; break; default: deviceTuner = "Unknown"; } return deviceTuner; } int SoapyRTLSDR::getE4000Gain(int stage, int gain) { static const int8_t if_stage1_gain[] = { -3, 6 }; static const int8_t if_stage23_gain[] = { 0, 3, 6, 9 }; static const int8_t if_stage4_gain[] = { 0, 1, 2 //, 2 }; static const int8_t if_stage56_gain[] = { 3, 6, 9, 12, 15 // , 15, 15, 15 // wat? }; const int8_t *if_stage = nullptr; int n_gains = 0; if (stage == 1) { if_stage = if_stage1_gain; n_gains = 2; } else if (stage == 2 || stage == 3) { if_stage = if_stage23_gain; n_gains = 4; } else if (stage == 4) { if_stage = if_stage4_gain; n_gains = 3; } else if (stage == 5 || stage == 6) { if_stage = if_stage56_gain; n_gains = 5; } if (n_gains && if_stage) { int gainMin = if_stage[0]; int gainMax = if_stage[n_gains-1]; if (gain > gainMax) { gain = gainMax; } if (gain < gainMin) { gain = gainMin; } for (int i = 0; i < n_gains-1; i++) { if (gain >= if_stage[i] && gain <= if_stage[i+1]) { gain = ((gain-if_stage[i]) < (if_stage[i+1]-gain))?if_stage[i]:if_stage[i+1]; } } } return gain; } rtlsdr_tuner SoapyRTLSDR::rtlStringToTuner(std::string tunerType) { rtlsdr_tuner deviceTuner = RTLSDR_TUNER_UNKNOWN; deviceTuner = RTLSDR_TUNER_UNKNOWN; if (tunerType == "Elonics E4000") deviceTuner = RTLSDR_TUNER_E4000; if (tunerType == "Fitipower FC0012") deviceTuner = RTLSDR_TUNER_FC0012; if (tunerType == "Fitipower FC0013") deviceTuner = RTLSDR_TUNER_FC0013; if (tunerType == "Fitipower FC2580") deviceTuner = RTLSDR_TUNER_FC2580; if (tunerType == "Rafael Micro R820T") deviceTuner = RTLSDR_TUNER_R820T; if (tunerType == "Rafael Micro R828D") deviceTuner = RTLSDR_TUNER_R828D; return deviceTuner; } SoapyRTLSDR-soapy-rtl-sdr-0.3.2/SoapyRTLSDR.hpp000066400000000000000000000236171400372211700210250ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Charles J. Cliffe * Copyright (c) 2015-2017 Josh Blum * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #pragma once #include #include #include #include #include #include #include #include #include typedef enum rtlsdrRXFormat { RTL_RX_FORMAT_FLOAT32, RTL_RX_FORMAT_INT16, RTL_RX_FORMAT_INT8 } rtlsdrRXFormat; #define DEFAULT_BUFFER_LENGTH (16 * 32 * 512) #define DEFAULT_NUM_BUFFERS 15 #define BYTES_PER_SAMPLE 2 class SoapyRTLSDR: public SoapySDR::Device { public: SoapyRTLSDR(const SoapySDR::Kwargs &args); ~SoapyRTLSDR(void); /******************************************************************* * Identification API ******************************************************************/ std::string getDriverKey(void) const; std::string getHardwareKey(void) const; SoapySDR::Kwargs getHardwareInfo(void) const; /******************************************************************* * Channels API ******************************************************************/ size_t getNumChannels(const int) const; bool getFullDuplex(const int direction, const size_t channel) const; /******************************************************************* * Stream API ******************************************************************/ std::vector getStreamFormats(const int direction, const size_t channel) const; std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const; SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const; SoapySDR::Stream *setupStream(const int direction, const std::string &format, const std::vector &channels = std::vector(), const SoapySDR::Kwargs &args = SoapySDR::Kwargs()); void closeStream(SoapySDR::Stream *stream); size_t getStreamMTU(SoapySDR::Stream *stream) const; int activateStream( SoapySDR::Stream *stream, const int flags = 0, const long long timeNs = 0, const size_t numElems = 0); int deactivateStream(SoapySDR::Stream *stream, const int flags = 0, const long long timeNs = 0); int readStream( SoapySDR::Stream *stream, void * const *buffs, const size_t numElems, int &flags, long long &timeNs, const long timeoutUs = 100000); /******************************************************************* * Direct buffer access API ******************************************************************/ size_t getNumDirectAccessBuffers(SoapySDR::Stream *stream); int getDirectAccessBufferAddrs(SoapySDR::Stream *stream, const size_t handle, void **buffs); int acquireReadBuffer( SoapySDR::Stream *stream, size_t &handle, const void **buffs, int &flags, long long &timeNs, const long timeoutUs = 100000); void releaseReadBuffer( SoapySDR::Stream *stream, const size_t handle); /******************************************************************* * Antenna API ******************************************************************/ std::vector listAntennas(const int direction, const size_t channel) const; void setAntenna(const int direction, const size_t channel, const std::string &name); std::string getAntenna(const int direction, const size_t channel) const; /******************************************************************* * Frontend corrections API ******************************************************************/ bool hasDCOffsetMode(const int direction, const size_t channel) const; bool hasFrequencyCorrection(const int direction, const size_t channel) const; void setFrequencyCorrection(const int direction, const size_t channel, const double value); double getFrequencyCorrection(const int direction, const size_t channel) const; /******************************************************************* * Gain API ******************************************************************/ std::vector listGains(const int direction, const size_t channel) const; bool hasGainMode(const int direction, const size_t channel) const; void setGainMode(const int direction, const size_t channel, const bool automatic); bool getGainMode(const int direction, const size_t channel) const; void setGain(const int direction, const size_t channel, const double value); void setGain(const int direction, const size_t channel, const std::string &name, const double value); double getGain(const int direction, const size_t channel, const std::string &name) const; SoapySDR::Range getGainRange(const int direction, const size_t channel, const std::string &name) const; /******************************************************************* * Frequency API ******************************************************************/ void setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs()); double getFrequency(const int direction, const size_t channel, const std::string &name) const; std::vector listFrequencies(const int direction, const size_t channel) const; SoapySDR::RangeList getFrequencyRange(const int direction, const size_t channel, const std::string &name) const; SoapySDR::ArgInfoList getFrequencyArgsInfo(const int direction, const size_t channel) const; /******************************************************************* * Sample Rate API ******************************************************************/ void setSampleRate(const int direction, const size_t channel, const double rate); double getSampleRate(const int direction, const size_t channel) const; std::vector listSampleRates(const int direction, const size_t channel) const; void setBandwidth(const int direction, const size_t channel, const double bw); double getBandwidth(const int direction, const size_t channel) const; std::vector listBandwidths(const int direction, const size_t channel) const; SoapySDR::RangeList getBandwidthRange(const int direction, const size_t channel) const; /******************************************************************* * Time API ******************************************************************/ std::vector listTimeSources(void) const; std::string getTimeSource(void) const; bool hasHardwareTime(const std::string &what = "") const; long long getHardwareTime(const std::string &what = "") const; void setHardwareTime(const long long timeNs, const std::string &what = ""); /******************************************************************* * Utility ******************************************************************/ static std::string rtlTunerToString(rtlsdr_tuner tunerType); static rtlsdr_tuner rtlStringToTuner(std::string tunerType); static int getE4000Gain(int stage, int gain); /******************************************************************* * Settings API ******************************************************************/ SoapySDR::ArgInfoList getSettingInfo(void) const; void writeSetting(const std::string &key, const std::string &value); std::string readSetting(const std::string &key) const; private: //device handle int deviceId; rtlsdr_dev_t *dev; //cached settings rtlsdrRXFormat rxFormat; rtlsdr_tuner tunerType; uint32_t sampleRate, centerFrequency, bandwidth; int ppm, directSamplingMode; size_t numBuffers, bufferLength, asyncBuffs; bool iqSwap, gainMode, offsetMode, digitalAGC, biasTee; double IFGain[6], tunerGain; std::atomic ticks; std::vector > _lut_32f; std::vector > _lut_swap_32f; std::vector > _lut_16i; std::vector > _lut_swap_16i; public: struct Buffer { unsigned long long tick; std::vector data; }; //async api usage std::thread _rx_async_thread; void rx_async_operation(void); void rx_callback(unsigned char *buf, uint32_t len); std::mutex _buf_mutex; std::condition_variable _buf_cond; std::vector _buffs; size_t _buf_head; size_t _buf_tail; std::atomic _buf_count; signed char *_currentBuff; std::atomic _overflowEvent; size_t _currentHandle; size_t bufferedElems; long long bufTicks; std::atomic resetBuffer; double gainMin, gainMax; }; SoapyRTLSDR-soapy-rtl-sdr-0.3.2/Streaming.cpp000066400000000000000000000364671400372211700207320ustar00rootroot00000000000000/* * The MIT License (MIT) * * Copyright (c) 2015 Charles J. Cliffe * Copyright (c) 2015-2017 Josh Blum * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "SoapyRTLSDR.hpp" #include #include #include #include //min #include //SHRT_MAX #include // memcpy std::vector SoapyRTLSDR::getStreamFormats(const int direction, const size_t channel) const { std::vector formats; formats.push_back(SOAPY_SDR_CS8); formats.push_back(SOAPY_SDR_CS16); formats.push_back(SOAPY_SDR_CF32); return formats; } std::string SoapyRTLSDR::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const { //check that direction is SOAPY_SDR_RX if (direction != SOAPY_SDR_RX) { throw std::runtime_error("RTL-SDR is RX only, use SOAPY_SDR_RX"); } fullScale = 128; return SOAPY_SDR_CS8; } SoapySDR::ArgInfoList SoapyRTLSDR::getStreamArgsInfo(const int direction, const size_t channel) const { //check that direction is SOAPY_SDR_RX if (direction != SOAPY_SDR_RX) { throw std::runtime_error("RTL-SDR is RX only, use SOAPY_SDR_RX"); } SoapySDR::ArgInfoList streamArgs; SoapySDR::ArgInfo bufflenArg; bufflenArg.key = "bufflen"; bufflenArg.value = std::to_string(DEFAULT_BUFFER_LENGTH); bufflenArg.name = "Buffer Size"; bufflenArg.description = "Number of bytes per buffer, multiples of 512 only."; bufflenArg.units = "bytes"; bufflenArg.type = SoapySDR::ArgInfo::INT; streamArgs.push_back(bufflenArg); SoapySDR::ArgInfo buffersArg; buffersArg.key = "buffers"; buffersArg.value = std::to_string(DEFAULT_NUM_BUFFERS); buffersArg.name = "Ring buffers"; buffersArg.description = "Number of buffers in the ring."; buffersArg.units = "buffers"; buffersArg.type = SoapySDR::ArgInfo::INT; streamArgs.push_back(buffersArg); SoapySDR::ArgInfo asyncbuffsArg; asyncbuffsArg.key = "asyncBuffs"; asyncbuffsArg.value = "0"; asyncbuffsArg.name = "Async buffers"; asyncbuffsArg.description = "Number of async usb buffers (advanced)."; asyncbuffsArg.units = "buffers"; asyncbuffsArg.type = SoapySDR::ArgInfo::INT; streamArgs.push_back(asyncbuffsArg); return streamArgs; } /******************************************************************* * Async thread work ******************************************************************/ static void _rx_callback(unsigned char *buf, uint32_t len, void *ctx) { //printf("_rx_callback\n"); SoapyRTLSDR *self = (SoapyRTLSDR *)ctx; self->rx_callback(buf, len); } void SoapyRTLSDR::rx_async_operation(void) { //printf("rx_async_operation\n"); rtlsdr_read_async(dev, &_rx_callback, this, asyncBuffs, bufferLength); //printf("rx_async_operation done!\n"); } void SoapyRTLSDR::rx_callback(unsigned char *buf, uint32_t len) { //printf("_rx_callback %d _buf_head=%d, numBuffers=%d\n", len, _buf_head, _buf_tail); // atomically add len to ticks but return the previous value unsigned long long tick = ticks.fetch_add(len); //overflow condition: the caller is not reading fast enough if (_buf_count == numBuffers) { _overflowEvent = true; return; } //copy into the buffer queue auto &buff = _buffs[_buf_tail]; buff.tick = tick; buff.data.resize(len); std::memcpy(buff.data.data(), buf, len); //increment the tail pointer _buf_tail = (_buf_tail + 1) % numBuffers; //increment buffers available under lock //to avoid race in acquireReadBuffer wait { std::lock_guard lock(_buf_mutex); _buf_count++; } //notify readStream() _buf_cond.notify_one(); } /******************************************************************* * Stream API ******************************************************************/ SoapySDR::Stream *SoapyRTLSDR::setupStream( const int direction, const std::string &format, const std::vector &channels, const SoapySDR::Kwargs &args) { if (direction != SOAPY_SDR_RX) { throw std::runtime_error("RTL-SDR is RX only, use SOAPY_SDR_RX"); } //check the channel configuration if (channels.size() > 1 or (channels.size() > 0 and channels.at(0) != 0)) { throw std::runtime_error("setupStream invalid channel selection"); } //check the format if (format == SOAPY_SDR_CF32) { SoapySDR_log(SOAPY_SDR_INFO, "Using format CF32."); rxFormat = RTL_RX_FORMAT_FLOAT32; } else if (format == SOAPY_SDR_CS16) { SoapySDR_log(SOAPY_SDR_INFO, "Using format CS16."); rxFormat = RTL_RX_FORMAT_INT16; } else if (format == SOAPY_SDR_CS8) { SoapySDR_log(SOAPY_SDR_INFO, "Using format CS8."); rxFormat = RTL_RX_FORMAT_INT8; } else { throw std::runtime_error( "setupStream invalid format '" + format + "' -- Only CS8, CS16 and CF32 are supported by SoapyRTLSDR module."); } if (rxFormat != RTL_RX_FORMAT_INT8 && !_lut_32f.size()) { SoapySDR_logf(SOAPY_SDR_DEBUG, "Generating RTL-SDR lookup tables"); // create lookup tables for (unsigned int i = 0; i <= 0xffff; i++) { # if (__BYTE_ORDER == __LITTLE_ENDIAN) float re = ((i & 0xff) - 127.4f) * (1.0f / 128.0f); float im = ((i >> 8) - 127.4f) * (1.0f / 128.0f); #else float re = ((i >> 8) - 127.4f) * (1.0f / 128.0f); float im = ((i & 0xff) - 127.4f) * (1.0f / 128.0f); #endif std::complex v32f, vs32f; v32f.real(re); v32f.imag(im); _lut_32f.push_back(v32f); vs32f.real(v32f.imag()); vs32f.imag(v32f.real()); _lut_swap_32f.push_back(vs32f); std::complex v16i, vs16i; v16i.real(int16_t((float(SHRT_MAX) * re))); v16i.imag(int16_t((float(SHRT_MAX) * im))); _lut_16i.push_back(v16i); vs16i.real(vs16i.imag()); vs16i.imag(vs16i.real()); _lut_swap_16i.push_back(vs16i); } } bufferLength = DEFAULT_BUFFER_LENGTH; if (args.count("bufflen") != 0) { try { int bufferLength_in = std::stoi(args.at("bufflen")); if (bufferLength_in > 0) { bufferLength = bufferLength_in; } } catch (const std::invalid_argument &){} } SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Using buffer length %d", bufferLength); numBuffers = DEFAULT_NUM_BUFFERS; if (args.count("buffers") != 0) { try { int numBuffers_in = std::stoi(args.at("buffers")); if (numBuffers_in > 0) { numBuffers = numBuffers_in; } } catch (const std::invalid_argument &){} } SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Using %d buffers", numBuffers); asyncBuffs = 0; if (args.count("asyncBuffs") != 0) { try { int asyncBuffs_in = std::stoi(args.at("asyncBuffs")); if (asyncBuffs_in > 0) { asyncBuffs = asyncBuffs_in; } } catch (const std::invalid_argument &){} } if (tunerType == RTLSDR_TUNER_E4000) { IFGain[0] = 6; IFGain[1] = 9; IFGain[2] = 3; IFGain[3] = 2; IFGain[4] = 3; IFGain[5] = 3; } else { for (int i = 0; i < 6; i++) { IFGain[i] = 0; } } tunerGain = rtlsdr_get_tuner_gain(dev) / 10.0; //clear async fifo counts _buf_tail = 0; _buf_count = 0; _buf_head = 0; //allocate buffers _buffs.resize(numBuffers); for (auto &buff : _buffs) buff.data.reserve(bufferLength); for (auto &buff : _buffs) buff.data.resize(bufferLength); return (SoapySDR::Stream *) this; } void SoapyRTLSDR::closeStream(SoapySDR::Stream *stream) { this->deactivateStream(stream, 0, 0); _buffs.clear(); } size_t SoapyRTLSDR::getStreamMTU(SoapySDR::Stream *stream) const { return bufferLength / BYTES_PER_SAMPLE; } int SoapyRTLSDR::activateStream( SoapySDR::Stream *stream, const int flags, const long long timeNs, const size_t numElems) { if (flags != 0) return SOAPY_SDR_NOT_SUPPORTED; resetBuffer = true; bufferedElems = 0; //start the async thread if (not _rx_async_thread.joinable()) { rtlsdr_reset_buffer(dev); _rx_async_thread = std::thread(&SoapyRTLSDR::rx_async_operation, this); } return 0; } int SoapyRTLSDR::deactivateStream(SoapySDR::Stream *stream, const int flags, const long long timeNs) { if (flags != 0) return SOAPY_SDR_NOT_SUPPORTED; if (_rx_async_thread.joinable()) { rtlsdr_cancel_async(dev); _rx_async_thread.join(); } return 0; } int SoapyRTLSDR::readStream( SoapySDR::Stream *stream, void * const *buffs, const size_t numElems, int &flags, long long &timeNs, const long timeoutUs) { //drop remainder buffer on reset if (resetBuffer and bufferedElems != 0) { bufferedElems = 0; this->releaseReadBuffer(stream, _currentHandle); } //this is the user's buffer for channel 0 void *buff0 = buffs[0]; //are elements left in the buffer? if not, do a new read. if (bufferedElems == 0) { int ret = this->acquireReadBuffer(stream, _currentHandle, (const void **)&_currentBuff, flags, timeNs, timeoutUs); if (ret < 0) return ret; bufferedElems = ret; } //otherwise just update return time to the current tick count else { flags |= SOAPY_SDR_HAS_TIME; timeNs = SoapySDR::ticksToTimeNs(bufTicks, sampleRate); } size_t returnedElems = std::min(bufferedElems, numElems); //convert into user's buff0 if (rxFormat == RTL_RX_FORMAT_FLOAT32) { float *ftarget = (float *) buff0; std::complex tmp; if (iqSwap) { for (size_t i = 0; i < returnedElems; i++) { tmp = _lut_swap_32f[*((uint16_t*) &_currentBuff[2 * i])]; ftarget[i * 2] = tmp.real(); ftarget[i * 2 + 1] = tmp.imag(); } } else { for (size_t i = 0; i < returnedElems; i++) { tmp = _lut_32f[*((uint16_t*) &_currentBuff[2 * i])]; ftarget[i * 2] = tmp.real(); ftarget[i * 2 + 1] = tmp.imag(); } } } else if (rxFormat == RTL_RX_FORMAT_INT16) { int16_t *itarget = (int16_t *) buff0; std::complex tmp; if (iqSwap) { for (size_t i = 0; i < returnedElems; i++) { tmp = _lut_swap_16i[*((uint16_t*) &_currentBuff[2 * i])]; itarget[i * 2] = tmp.real(); itarget[i * 2 + 1] = tmp.imag(); } } else { for (size_t i = 0; i < returnedElems; i++) { tmp = _lut_16i[*((uint16_t*) &_currentBuff[2 * i])]; itarget[i * 2] = tmp.real(); itarget[i * 2 + 1] = tmp.imag(); } } } else if (rxFormat == RTL_RX_FORMAT_INT8) { int8_t *itarget = (int8_t *) buff0; if (iqSwap) { for (size_t i = 0; i < returnedElems; i++) { itarget[i * 2] = _currentBuff[i * 2 + 1]-128; itarget[i * 2 + 1] = _currentBuff[i * 2]-128; } } else { for (size_t i = 0; i < returnedElems; i++) { itarget[i * 2] = _currentBuff[i * 2]-128; itarget[i * 2 + 1] = _currentBuff[i * 2 + 1]-128; } } } //bump variables for next call into readStream bufferedElems -= returnedElems; _currentBuff += returnedElems*BYTES_PER_SAMPLE; bufTicks += returnedElems; //for the next call to readStream if there is a remainder //return number of elements written to buff0 if (bufferedElems != 0) flags |= SOAPY_SDR_MORE_FRAGMENTS; else this->releaseReadBuffer(stream, _currentHandle); return returnedElems; } /******************************************************************* * Direct buffer access API ******************************************************************/ size_t SoapyRTLSDR::getNumDirectAccessBuffers(SoapySDR::Stream *stream) { return _buffs.size(); } int SoapyRTLSDR::getDirectAccessBufferAddrs(SoapySDR::Stream *stream, const size_t handle, void **buffs) { buffs[0] = (void *)_buffs[handle].data.data(); return 0; } int SoapyRTLSDR::acquireReadBuffer( SoapySDR::Stream *stream, size_t &handle, const void **buffs, int &flags, long long &timeNs, const long timeoutUs) { //reset is issued by various settings //to drain old data out of the queue if (resetBuffer) { //drain all buffers from the fifo _buf_head = (_buf_head + _buf_count.exchange(0)) % numBuffers; resetBuffer = false; _overflowEvent = false; } //handle overflow from the rx callback thread if (_overflowEvent) { //drain the old buffers from the fifo _buf_head = (_buf_head + _buf_count.exchange(0)) % numBuffers; _overflowEvent = false; SoapySDR::log(SOAPY_SDR_SSI, "O"); return SOAPY_SDR_OVERFLOW; } //wait for a buffer to become available if (_buf_count == 0) { std::unique_lock lock(_buf_mutex); _buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs), [this]{return _buf_count != 0;}); if (_buf_count == 0) return SOAPY_SDR_TIMEOUT; } //extract handle and buffer handle = _buf_head; _buf_head = (_buf_head + 1) % numBuffers; bufTicks = _buffs[handle].tick; timeNs = SoapySDR::ticksToTimeNs(_buffs[handle].tick, sampleRate); buffs[0] = (void *)_buffs[handle].data.data(); flags = SOAPY_SDR_HAS_TIME; //return number available return _buffs[handle].data.size() / BYTES_PER_SAMPLE; } void SoapyRTLSDR::releaseReadBuffer( SoapySDR::Stream *stream, const size_t handle) { //TODO this wont handle out of order releases _buf_count--; } SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/000077500000000000000000000000001400372211700174775ustar00rootroot00000000000000SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/changelog000066400000000000000000000026651400372211700213620ustar00rootroot00000000000000soapyrtlsdr (0.3.2-1) unstable; urgency=low * Release 0.3.2 (2021-01-25) -- Josh Blum Mon, 25 Jan 2021 23:10:37 -0000 soapyrtlsdr (0.3.1-1) unstable; urgency=low * Release 0.3.1 (2020-07-20) -- Josh Blum Mon, 20 Jul 2020 10:42:53 -0000 soapyrtlsdr (0.3.0-1) unstable; urgency=low * Release 0.3.0 (2018-12-07) -- Josh Blum Fri, 07 Dec 2018 21:17:42 -0000 soapyrtlsdr (0.2.5-1) unstable; urgency=low * Release 0.2.5 (2018-05-05) -- Josh Blum Sat, 05 May 2018 20:40:24 -0000 soapyrtlsdr (0.2.4-1) unstable; urgency=low * Release 0.2.4 (2017-06-15) -- Josh Blum Thu, 15 Jun 2017 17:48:13 -0000 soapyrtlsdr (0.2.3-1) unstable; urgency=low * Release 0.2.3 (2017-04-29) -- Josh Blum Sat, 29 Apr 2017 15:04:19 -0000 soapyrtlsdr (0.2.2) unstable; urgency=low * Release 0.2.2 (2016-09-01) -- Josh Blum Thu, 01 Sep 2016 21:23:34 -0700 soapyrtlsdr (0.2.1) unstable; urgency=low * Release 0.2.1 (2016-04-25) -- Josh Blum Mon, 25 Apr 2016 07:44:39 -0400 soapyrtlsdr (0.2.0) unstable; urgency=low * Release 0.2.0 (2015-12-10) -- Josh Blum Fri, 16 Oct 2015 18:40:55 -0700 soapyrtlsdr (0.1.0) unstable; urgency=low * Release 0.1.0 (2015-10-10) -- Josh Blum Sat, 10 Oct 2015 11:19:07 -0700 SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/compat000066400000000000000000000000021400372211700206750ustar00rootroot000000000000009 SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/control000066400000000000000000000025751400372211700211130ustar00rootroot00000000000000Source: soapyrtlsdr Section: hamradio Priority: optional Maintainer: Charles J. Cliffe Uploaders: Josh Blum Build-Depends: debhelper (>= 9.0.0), cmake, libsoapysdr-dev, librtlsdr-dev Standards-Version: 4.5.0 Homepage: https://github.com/pothosware/SoapyRTLSDR/wiki Vcs-Git: https://github.com/pothosware/SoapyRTLSDR.git Vcs-Browser: https://github.com/pothosware/SoapyRTLSDR Package: soapysdr0.7-module-rtlsdr Architecture: any Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends} Description: RTL-SDR device support for SoapySDR The Soapy RTL-SDR project provides a SoapySDR hardware support module. Using this, any program using SoapySDR to interface to software defined radio hardware can make use of low cost DVB-T/DAB+ USB dongles based on the Realtek RTL2832U chip as receivers. Package: soapysdr-module-rtlsdr Architecture: all Depends: soapysdr0.7-module-rtlsdr, ${misc:Depends} Description: RTL-SDR device support for SoapySDR (default version) The Soapy RTL-SDR project provides a SoapySDR hardware support module. Using this, any program using SoapySDR to interface to software defined radio hardware can make use of low cost DVB-T/DAB+ USB dongles based on the Realtek RTL2832U chip as receivers. . This is an empty dependency package that pulls in the RTL-SDR module for the default version of libsoapysdr. SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/copyright000066400000000000000000000023651400372211700214400ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: soapyrtlsdr Source: https://github.com/pothosware/SoapyRTLSDR/wiki Files: * Copyright: Copyright (c) 2015 Charles J. Cliffe License: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/docs000066400000000000000000000000121400372211700203430ustar00rootroot00000000000000README.md SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/rules000077500000000000000000000005641400372211700205640ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ --buildsystem=cmake --parallel override_dh_auto_configure: dh_auto_configure -- -DLIB_SUFFIX="/$(DEB_HOST_MULTIARCH)" override_dh_installchangelogs: dh_installchangelogs Changelog.txt SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/soapysdr0.7-module-rtlsdr.install000066400000000000000000000000121400372211700257440ustar00rootroot00000000000000usr/lib/* SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/source/000077500000000000000000000000001400372211700207775ustar00rootroot00000000000000SoapyRTLSDR-soapy-rtl-sdr-0.3.2/debian/source/format000066400000000000000000000000141400372211700222050ustar00rootroot000000000000003.0 (quilt)