[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: [![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.
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