[hamradio-commits] [soapyrtlsdr] 01/02: Imported Upstream version 0.2.1
Andreas E. Bombe
aeb at moszumanska.debian.org
Tue Aug 16 02:18:51 UTC 2016
This is an automated email from the git hooks/post-receive script.
aeb pushed a commit to branch master
in repository soapyrtlsdr.
commit 9de7352750399274fc6312c1fc54a6d37bdb0e8b
Author: Andreas Bombe <aeb at debian.org>
Date: Sat Jul 9 00:23:38 2016 +0200
Imported Upstream version 0.2.1
---
.gitignore | 1 +
.travis.yml | 56 +++++
CMakeLists.txt | 60 +++++
Changelog.txt | 16 ++
FindRTLSDR.cmake | 58 +++++
LICENSE.txt | 21 ++
README.md | 38 +++
Registation.cpp | 163 +++++++++++++
Settings.cpp | 665 +++++++++++++++++++++++++++++++++++++++++++++++++++
SoapyRTLSDR.hpp | 252 +++++++++++++++++++
Streaming.cpp | 474 ++++++++++++++++++++++++++++++++++++
debian/changelog | 17 ++
debian/compat | 1 +
debian/control | 23 ++
debian/copyright | 24 ++
debian/docs | 1 +
debian/rules | 21 ++
debian/source/format | 1 +
18 files changed, 1892 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..378eac2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..de8eea7
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,56 @@
+########################################################################
+## 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
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..d6b8955
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,60 @@
+########################################################################
+# 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})
+
+#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)
+
+set(OTHER_LIBS "" CACHE STRING "Other libraries")
+
+SOAPY_SDR_MODULE_UTIL(
+ TARGET rtlsdrSupport
+ SOURCES
+ SoapyRTLSDR.hpp
+ Registation.cpp
+ Settings.cpp
+ Streaming.cpp
+ LIBRARIES
+ ${RTLSDR_LIBRARIES}
+ ${OTHER_LIBS}
+)
diff --git a/Changelog.txt b/Changelog.txt
new file mode 100644
index 0000000..8e481e0
--- /dev/null
+++ b/Changelog.txt
@@ -0,0 +1,16 @@
+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
diff --git a/FindRTLSDR.cmake b/FindRTLSDR.cmake
new file mode 100644
index 0000000..5b82aa8
--- /dev/null
+++ b/FindRTLSDR.cmake
@@ -0,0 +1,58 @@
+#
+# 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)
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..439cd08
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+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.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8bcdd8f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# Soapy SDR module for RTL-SDR
+
+##Build Status
+
+- Travis: [](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.
diff --git a/Registation.cpp b/Registation.cpp
new file mode 100644
index 0000000..df16da5
--- /dev/null
+++ b/Registation.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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 <SoapySDR/Registry.hpp>
+#include <cstdlib> //malloc
+
+static std::vector<SoapySDR::Kwargs> findRTLSDR(const SoapySDR::Kwargs &args)
+{
+ std::vector<SoapySDR::Kwargs> results;
+
+ char manufact[256], product[256], serial[256];
+
+ int this_count = rtlsdr_get_device_count();
+
+ if (!SoapyRTLSDR::rtl_devices.size() || SoapyRTLSDR::rtl_count != this_count)
+ {
+ SoapyRTLSDR::rtl_count = this_count;
+
+ if (SoapyRTLSDR::rtl_devices.size())
+ {
+ SoapyRTLSDR::rtl_devices.erase(SoapyRTLSDR::rtl_devices.begin(), SoapyRTLSDR::rtl_devices.end());
+ }
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Devices: %d", SoapyRTLSDR::rtl_count);
+
+ for (int i = 0; i < SoapyRTLSDR::rtl_count; i++)
+ {
+ SoapySDR::Kwargs devInfo;
+
+ std::string deviceName(rtlsdr_get_device_name(i));
+ std::string deviceManufacturer;
+ std::string deviceProduct;
+ std::string deviceTuner;
+ std::string deviceSerial;
+
+ bool deviceAvailable = false;
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Device #%d: %s", i, deviceName.c_str());
+ if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) == 0)
+ {
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "\tManufacturer: %s, Product Name: %s, Serial: %s", manufact, product,
+ serial);
+
+ deviceSerial = serial;
+ deviceProduct = product;
+ deviceManufacturer = manufact;
+
+ rtlsdr_dev_t *devTest;
+ if (rtlsdr_open(&devTest, i) == 0)
+ {
+ deviceAvailable = true;
+
+ if (!SoapyRTLSDR::gainMax)
+ {
+ int num_gains = rtlsdr_get_tuner_gains(devTest, NULL);
+ int *gains = (int *) malloc(sizeof(int) * num_gains);
+
+ num_gains = rtlsdr_get_tuner_gains(devTest, gains);
+
+ int rangeMin = gains[0], rangeMax = gains[0];
+
+ for (int g = 0; g < num_gains; g++)
+ {
+ if (gains[g] < rangeMin)
+ {
+ rangeMin = gains[g];
+ }
+ if (gains[g] > rangeMax)
+ {
+ rangeMax = gains[g];
+ }
+ }
+ free(gains);
+
+ SoapyRTLSDR::gainMin = (double) rangeMin / 10.0;
+ SoapyRTLSDR::gainMax = (double) rangeMax / 10.0;
+ }
+
+ deviceTuner = SoapyRTLSDR::rtlTunerToString(rtlsdr_get_tuner_type(devTest));
+
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "\t Tuner type: %s", deviceTuner.c_str());
+
+ rtlsdr_close(devTest);
+ }
+ }
+
+ if (!deviceAvailable)
+ {
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "\tUnable to access device #%d (in use?)", i);
+ }
+
+ std::string deviceLabel = std::string(rtlsdr_get_device_name(i)) + " :: " + deviceSerial;
+
+ devInfo["rtl"] = std::to_string(i);
+ devInfo["label"] = deviceLabel;
+ devInfo["available"] = deviceAvailable ? "Yes" : "No";
+ devInfo["product"] = deviceProduct;
+ devInfo["serial"] = deviceSerial;
+ devInfo["manufacturer"] = deviceManufacturer;
+ devInfo["tuner"] = deviceTuner;
+ SoapyRTLSDR::rtl_devices.push_back(devInfo);
+ }
+ }
+
+ //filtering
+ for (int i = 0; i < SoapyRTLSDR::rtl_count; i++)
+ {
+ SoapySDR::Kwargs devInfo = SoapyRTLSDR::rtl_devices[i];
+ if (args.count("rtl") != 0)
+ {
+ if (args.at("rtl") != devInfo.at("rtl"))
+ {
+ continue;
+ }
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Found device by index %s", devInfo.at("rtl").c_str());
+ }
+ else if (args.count("serial") != 0)
+ {
+ if (devInfo.at("serial") != args.at("serial"))
+ {
+ continue;
+ }
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Found device by serial %s", args.at("serial").c_str());
+ }
+ else if (args.count("label") != 0)
+ {
+ if (devInfo.at("label") != args.at("label"))
+ {
+ continue;
+ }
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Found device by label %s", args.at("label").c_str());
+ }
+ results.push_back(SoapyRTLSDR::rtl_devices[i]);
+ }
+ 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);
diff --git a/Settings.cpp b/Settings.cpp
new file mode 100644
index 0000000..ccef7be
--- /dev/null
+++ b/Settings.cpp
@@ -0,0 +1,665 @@
+/*
+ * 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"
+
+int SoapyRTLSDR::rtl_count;
+std::vector<SoapySDR::Kwargs> SoapyRTLSDR::rtl_devices;
+double SoapyRTLSDR::gainMin;
+double SoapyRTLSDR::gainMax;
+
+SoapyRTLSDR::SoapyRTLSDR(const SoapySDR::Kwargs &args)
+{
+ if (!SoapyRTLSDR::rtl_count)
+ {
+ throw std::runtime_error("RTL-SDR device not found.");
+ }
+
+ deviceId = -1;
+ dev = NULL;
+
+ rxFormat = RTL_RX_FORMAT_FLOAT32;
+ tunerType = RTLSDR_TUNER_R820T;
+
+ sampleRate = 2048000;
+ centerFrequency = 100000000;
+
+ ppm = 0;
+ directSamplingMode = 0;
+ numBuffers = DEFAULT_NUM_BUFFERS;
+ bufferLength = DEFAULT_BUFFER_LENGTH;
+
+ iqSwap = false;
+ agcMode = false;
+ offsetMode = false;
+
+ bufferedElems = 0;
+ resetBuffer = false;
+
+ if (args.count("rtl") != 0)
+ {
+ try
+ {
+ deviceId = std::stoi(args.at("rtl"));
+ }
+ catch (const std::invalid_argument &)
+ {
+ }
+ if (deviceId < 0 || deviceId >= SoapyRTLSDR::rtl_count)
+ {
+ throw std::runtime_error(
+ "device index 'rtl' out of range [0 .. " + std::to_string(SoapyRTLSDR::rtl_count) + "].");
+ }
+
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Found RTL-SDR Device using device index parameter 'rtl' = %d", deviceId);
+ }
+ else if (args.count("serial") != 0)
+ {
+ std::string deviceSerialFind = args.at("serial");
+
+ for (int i = 0; i < SoapyRTLSDR::rtl_count; i++)
+ {
+ SoapySDR::Kwargs devInfo = SoapyRTLSDR::rtl_devices[i];
+ if (devInfo.at("serial") == deviceSerialFind)
+ {
+ SoapySDR_logf(SOAPY_SDR_DEBUG,
+ "Found RTL-SDR Device #%d by serial %s -- Manufacturer: %s, Product Name: %s, Serial: %s", i,
+ deviceSerialFind.c_str(), devInfo.at("manufacturer").c_str(), devInfo.at("product").c_str(),
+ devInfo.at("serial").c_str());
+ deviceId = i;
+ break;
+ }
+ }
+ }
+ else if (args.count("label") != 0)
+ {
+ std::string labelFind = args.at("label");
+ for (int i = 0; i < SoapyRTLSDR::rtl_count; i++)
+ {
+ SoapySDR::Kwargs devInfo = SoapyRTLSDR::rtl_devices[i];
+ if (devInfo.at("label") == labelFind)
+ {
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Found RTL-SDR Device #%d by name: %s", devInfo.at("label").c_str());
+ deviceId = i;
+ break;
+ }
+ }
+ }
+
+ if (deviceId == -1)
+ {
+ throw std::runtime_error("Unable to find requested RTL-SDR device.");
+ }
+
+ 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);
+
+ rtlsdr_open(&dev, deviceId);
+}
+
+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
+{
+ return "RTLSDR";
+}
+
+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["rtl"] = std::to_string(deviceId);
+
+ return args;
+}
+
+/*******************************************************************
+ * Channels API
+ ******************************************************************/
+
+size_t SoapyRTLSDR::getNumChannels(const int dir) const
+{
+ return (dir == SOAPY_SDR_RX) ? 1 : 0;
+}
+
+/*******************************************************************
+ * Antenna API
+ ******************************************************************/
+
+std::vector<std::string> SoapyRTLSDR::listAntennas(const int direction, const size_t channel) const
+{
+ std::vector<std::string> 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;
+}
+
+/*******************************************************************
+ * Gain API
+ ******************************************************************/
+
+std::vector<std::string> SoapyRTLSDR::listGains(const int direction, const size_t channel) const
+{
+ //list available gain elements,
+ //the functions below have a "name" parameter
+ std::vector<std::string> 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)
+{
+ agcMode = automatic;
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting RTL-SDR AGC: %s", automatic ? "Automatic" : "Manual");
+ rtlsdr_set_agc_mode(dev, agcMode ? 1 : 0);
+}
+
+bool SoapyRTLSDR::getGainMode(const int direction, const size_t channel) const
+{
+ return SoapySDR::Device::getGainMode(direction, channel);
+}
+
+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(SoapyRTLSDR::gainMin, SoapyRTLSDR::gainMax);
+ } else {
+ return SoapySDR::Range(SoapyRTLSDR::gainMin, SoapyRTLSDR::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")
+ {
+ centerFrequency = (uint32_t) frequency;
+ resetBuffer = true;
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting center freq: %d", centerFrequency);
+ rtlsdr_set_center_freq(dev, centerFrequency);
+ }
+
+ if (name == "CORR")
+ {
+ ppm = (int) frequency;
+ rtlsdr_set_freq_correction(dev, ppm);
+ }
+}
+
+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<std::string> SoapyRTLSDR::listFrequencies(const int direction, const size_t channel) const
+{
+ std::vector<std::string> 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)
+{
+ sampleRate = rate;
+ resetBuffer = true;
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting sample rate: %d", sampleRate);
+ rtlsdr_set_sample_rate(dev, sampleRate);
+}
+
+double SoapyRTLSDR::getSampleRate(const int direction, const size_t channel) const
+{
+ return sampleRate;
+}
+
+std::vector<double> SoapyRTLSDR::listSampleRates(const int direction, const size_t channel) const
+{
+ std::vector<double> 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)
+{
+ SoapySDR::Device::setBandwidth(direction, channel, bw);
+}
+
+double SoapyRTLSDR::getBandwidth(const int direction, const size_t channel) const
+{
+ return SoapySDR::Device::getBandwidth(direction, channel);
+}
+
+std::vector<double> SoapyRTLSDR::listBandwidths(const int direction, const size_t channel) const
+{
+ std::vector<double> results;
+
+ return results;
+}
+
+/*******************************************************************
+ * 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_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);
+ }
+}
+
+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";
+ }
+
+ 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;
+}
+
diff --git a/SoapyRTLSDR.hpp b/SoapyRTLSDR.hpp
new file mode 100644
index 0000000..47164df
--- /dev/null
+++ b/SoapyRTLSDR.hpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <SoapySDR/Device.hpp>
+#include <SoapySDR/Logger.h>
+#include <SoapySDR/Types.h>
+#include <rtl-sdr.h>
+#include <stdexcept>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+
+typedef enum rtlsdrRXFormat
+{
+ RTL_RX_FORMAT_FLOAT32, RTL_RX_FORMAT_INT16, RTL_RX_FORMAT_INT8
+} rtlsdrRXFormat;
+
+#define DEFAULT_BUFFER_LENGTH 16384
+#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;
+
+ /*******************************************************************
+ * Stream API
+ ******************************************************************/
+
+ std::vector<std::string> 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<size_t> &channels =
+ std::vector<size_t>(), 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<std::string> 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;
+
+ /*******************************************************************
+ * Gain API
+ ******************************************************************/
+
+ std::vector<std::string> 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<std::string> 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<double> 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<double> listBandwidths(const int direction, const size_t channel) const;
+
+ /*******************************************************************
+ * 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;
+ int ppm, directSamplingMode;
+ size_t numBuffers, bufferLength;
+ bool iqSwap, agcMode, offsetMode;
+ double IFGain[6], tunerGain;
+
+ std::vector<std::complex<float> > _lut_32f;
+ std::vector<std::complex<float> > _lut_swap_32f;
+ std::vector<std::complex<int16_t> > _lut_16i;
+ std::vector<std::complex<int16_t> > _lut_swap_16i;
+
+public:
+ //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<std::vector<signed char> > _buffs;
+ size_t _buf_head;
+ size_t _buf_tail;
+ size_t _buf_count;
+ signed char *_currentBuff;
+ bool _overflowEvent;
+ size_t _currentHandle;
+ size_t bufferedElems;
+ bool resetBuffer;
+
+ static int rtl_count;
+ static std::vector<SoapySDR::Kwargs> rtl_devices;
+ static double gainMin, gainMax;
+};
diff --git a/Streaming.cpp b/Streaming.cpp
new file mode 100644
index 0000000..18f0306
--- /dev/null
+++ b/Streaming.cpp
@@ -0,0 +1,474 @@
+/*
+ * 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 <SoapySDR/Logger.hpp>
+#include <algorithm> //min
+#include <climits> //SHRT_MAX
+#include <cstring> // memcpy
+
+
+std::vector<std::string> SoapyRTLSDR::getStreamFormats(const int direction, const size_t channel) const {
+ std::vector<std::string> formats;
+
+ formats.push_back("CS8");
+ formats.push_back("CS16");
+ formats.push_back("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 "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 = "16384";
+ 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 = "15";
+ buffersArg.name = "Buffer Count";
+ buffersArg.description = "Number of buffers per read.";
+ buffersArg.units = "buffers";
+ buffersArg.type = SoapySDR::ArgInfo::INT;
+
+ streamArgs.push_back(buffersArg);
+
+ 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, numBuffers, bufferLength);
+ //printf("rx_async_operation done!\n");
+}
+
+void SoapyRTLSDR::rx_callback(unsigned char *buf, uint32_t len)
+{
+ std::unique_lock<std::mutex> lock(_buf_mutex);
+
+ //printf("_rx_callback %d _buf_head=%d, numBuffers=%d\n", len, _buf_head, _buf_tail);
+
+ //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.resize(len);
+ std::memcpy(buff.data(), buf, len);
+
+ //increment the tail pointer
+ _buf_tail = (_buf_tail + 1) % numBuffers;
+ _buf_count++;
+
+ //notify readStream()
+ _buf_cond.notify_one();
+}
+
+/*******************************************************************
+ * Stream API
+ ******************************************************************/
+
+SoapySDR::Stream *SoapyRTLSDR::setupStream(
+ const int direction,
+ const std::string &format,
+ const std::vector<size_t> &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 == "CF32")
+ {
+ SoapySDR_log(SOAPY_SDR_INFO, "Using format CF32.");
+ rxFormat = RTL_RX_FORMAT_FLOAT32;
+ }
+ else if (format == "CS16")
+ {
+ SoapySDR_log(SOAPY_SDR_INFO, "Using format CS16.");
+ rxFormat = RTL_RX_FORMAT_INT16;
+ }
+ else if (format == "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)
+ std::complex<float> v32f, vs32f;
+
+ v32f.real((float(i & 0xff) - 127.4f) * (1.0f / 128.0f));
+ v32f.imag((float(i >> 8) - 127.4f) * (1.0f / 128.0f));
+ _lut_32f.push_back(v32f);
+
+ vs32f.real(v32f.imag());
+ vs32f.imag(v32f.real());
+ _lut_swap_32f.push_back(vs32f);
+
+ std::complex<int16_t> v16i, vs16i;
+
+ v16i.real(int16_t((float(SHRT_MAX) * ((float(i & 0xff) - 127.4f) * (1.0f / 128.0f)))));
+ v16i.imag(int16_t((float(SHRT_MAX) * ((float(i >> 8) - 127.4f) * (1.0f / 128.0f)))));
+ _lut_16i.push_back(v16i);
+
+ vs16i.real(vs16i.imag());
+ vs16i.imag(vs16i.real());
+ _lut_swap_16i.push_back(vs16i);
+
+#else // BIG_ENDIAN
+#error TODO
+ // tmp_swap.imag = tmp.real = (float(i >> 8) - 127.4f) * (1.0f/128.0f);
+ // tmp_swap.real = tmp.imag = (float(i & 0xff) - 127.4f) * (1.0f/128.0f);
+ // _lut.push_back(tmp);
+ // _lut_swap.push_back(tmp_swap);
+#endif
+ }
+ }
+
+
+ if (args.count("buflen") != 0)
+ {
+ try
+ {
+ int bufferLength_in = std::stoi(args.at("buflen"));
+ if (bufferLength_in > 0)
+ {
+ bufferLength = bufferLength_in;
+ }
+ }
+ catch (const std::invalid_argument &){}
+ }
+ SoapySDR_logf(SOAPY_SDR_DEBUG, "RTL-SDR Using buffer length %d", bufferLength);
+
+ 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);
+
+ 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);
+
+ //clear async fifo counts
+ _buf_tail = 0;
+ _buf_count = 0;
+ _buf_head = 0;
+
+ //allocate buffers
+ _buffs.resize(numBuffers);
+ for (auto &buff : _buffs) buff.reserve(bufferLength);
+ for (auto &buff : _buffs) buff.resize(bufferLength);
+
+ return (SoapySDR::Stream *) this;
+}
+
+void SoapyRTLSDR::closeStream(SoapySDR::Stream *stream)
+{
+ _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)
+{
+ //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;
+ }
+
+ size_t returnedElems = std::min(bufferedElems, numElems);
+
+ //convert into user's buff0
+ if (rxFormat == RTL_RX_FORMAT_FLOAT32)
+ {
+ float *ftarget = (float *) buff0;
+ std::complex<float> 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<int16_t> 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]-127;
+ itarget[i * 2 + 1] = _currentBuff[i * 2]-127;
+ }
+ }
+ else
+ {
+ for (size_t i = 0; i < returnedElems; i++)
+ {
+ itarget[i * 2] = _currentBuff[i * 2]-127;
+ itarget[i * 2 + 1] = _currentBuff[i * 2 + 1]-127;
+ }
+ }
+ }
+
+ //bump variables for next call into readStream
+ bufferedElems -= returnedElems;
+ _currentBuff += returnedElems*BYTES_PER_SAMPLE;
+
+ //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();
+ return 0;
+}
+
+int SoapyRTLSDR::acquireReadBuffer(
+ SoapySDR::Stream *stream,
+ size_t &handle,
+ const void **buffs,
+ int &flags,
+ long long &timeNs,
+ const long timeoutUs)
+{
+ std::unique_lock <std::mutex> lock(_buf_mutex);
+
+ //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) % numBuffers;
+ _buf_count = 0;
+ 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) % numBuffers;
+ _buf_count = 0;
+ _overflowEvent = false;
+ SoapySDR::log(SOAPY_SDR_SSI, "O");
+ return SOAPY_SDR_OVERFLOW;
+ }
+
+ //wait for a buffer to become available
+ while (_buf_count == 0)
+ {
+ _buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs));
+ if (_buf_count == 0) return SOAPY_SDR_TIMEOUT;
+ }
+
+ //extract handle and buffer
+ handle = _buf_head;
+ _buf_head = (_buf_head + 1) % numBuffers;
+ buffs[0] = (void *)_buffs[handle].data();
+ flags = 0;
+
+ //return number available
+ return _buffs[handle].size() / BYTES_PER_SAMPLE;
+}
+
+void SoapyRTLSDR::releaseReadBuffer(
+ SoapySDR::Stream *stream,
+ const size_t handle)
+{
+ //TODO this wont handle out of order releases
+ std::unique_lock <std::mutex> lock(_buf_mutex);
+ _buf_count--;
+}
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..52761de
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,17 @@
+soapyrtlsdr (0.2.1) unstable; urgency=low
+
+ * Release 0.2.1 (2016-04-25)
+
+ -- Josh Blum <josh at pothosware.com> Mon, 25 Apr 2016 07:44:39 -0400
+
+soapyrtlsdr (0.2.0) unstable; urgency=low
+
+ * Release 0.2.0 (2015-12-10)
+
+ -- Josh Blum <josh at pothosware.com> Fri, 16 Oct 2015 18:40:55 -0700
+
+soapyrtlsdr (0.1.0) unstable; urgency=low
+
+ * Release 0.1.0 (2015-10-10)
+
+ -- Josh Blum <josh at pothosware.com> Sat, 10 Oct 2015 11:19:07 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..2d51eff
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,23 @@
+Source: soapyrtlsdr
+Section: libs
+Priority: optional
+Maintainer: Charles J. Cliffe <cj at cubicproductions.com>
+Uploaders: Josh Blum <josh at pothosware.com>
+Build-Depends:
+ debhelper (>= 9.0.0),
+ cmake,
+ libsoapysdr-dev,
+ librtlsdr-dev
+Standards-Version: 3.9.5
+Homepage: https://github.com/pothosware/SoapyRTLSDR/wiki
+Vcs-Git: https://github.com/pothosware/SoapyRTLSDR.git
+Vcs-Browser: https://github.com/pothosware/SoapyRTLSDR
+
+Package: soapysdr-rtlsdr
+Section: libs
+Architecture: any
+Conflicts: soapyosmo-rtlsdr
+Replaces: soapyosmo-rtlsdr
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Soapy RTL-SDR - RTL-SDR device support for Soapy SDR.
+ A Soapy module that supports RTL-SDR devices within the Soapy API.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..8e7fb79
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,24 @@
+Format: 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.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..b43bf86
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1 @@
+README.md
diff --git a/debian/rules b/debian/rules
new file mode 100644
index 0000000..f7d5e49
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,21 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+export DEB_HOST_MULTIARCH
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This has to be exported to make some magic below work.
+export DH_OPTIONS
+
+
+%:
+ dh $@ --buildsystem=cmake --parallel
+
+override_dh_auto_configure:
+ dh_auto_configure -- -DLIB_SUFFIX="/$(DEB_HOST_MULTIARCH)"
+
+override_dh_installchangelogs:
+ dh_installchangelogs Changelog.txt
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/soapyrtlsdr.git
More information about the pkg-hamradio-commits
mailing list