[hamradio-commits] [soapyairspy] 01/03: New upstream version 0.1.0

Andreas E. Bombe aeb at moszumanska.debian.org
Sun Dec 11 23:36:35 UTC 2016


This is an automated email from the git hooks/post-receive script.

aeb pushed a commit to branch master
in repository soapyairspy.

commit 3a90baf5b7e0f4dcf853f2f235e09f251bb8db91
Author: Andreas Bombe <aeb at debian.org>
Date:   Mon Dec 12 00:05:54 2016 +0100

    New upstream version 0.1.0
---
 .gitignore                                 |   2 +
 CMakeLists.txt                             |  59 +++++
 Changelog.txt                              |   4 +
 FindLibAIRSPY.cmake                        |  24 ++
 LICENSE.txt                                |  21 ++
 LibFindMacros.cmake                        |  99 +++++++
 README.md                                  |  10 +
 Registation.cpp                            | 146 ++++++++++
 Settings.cpp                               | 410 +++++++++++++++++++++++++++++
 SoapyAirspy.hpp                            | 237 +++++++++++++++++
 Streaming.cpp                              | 337 ++++++++++++++++++++++++
 debian/changelog                           |   5 +
 debian/compat                              |   1 +
 debian/control                             |  30 +++
 debian/copyright                           |  24 ++
 debian/docs                                |   1 +
 debian/rules                               |  16 ++
 debian/soapysdr0.5-2-module-airspy.install |   1 +
 debian/source/format                       |   1 +
 19 files changed, 1428 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6f31401
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+build/
+.vscode/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..b4c6a03
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,59 @@
+###################################################
+# Build Soapy SDR support module for Airspy Devices
+###################################################
+
+cmake_minimum_required(VERSION 2.8.7)
+
+project(SoapyAirspy 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(LibAIRSPY)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${LIBAIRSPY_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 AIRSPY_LIBS -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)
+
+# IF (APPLE)
+#  ADD_DEFINITIONS(
+#    -D__MACOSX_CORE__
+#  )
+# FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation)
+#SET (AIRSPY_LIBS ${COREFOUNDATION_LIBRARY} ${AIRSPY_LIBS} )
+# ENDIF (APPLE)
+
+list(APPEND AIRSPY_LIBS ${LIBAIRSPY_LIBRARIES})
+
+SOAPY_SDR_MODULE_UTIL(
+    TARGET airspySupport
+    SOURCES
+        SoapyAirspy.hpp
+        Registation.cpp
+        Settings.cpp
+        Streaming.cpp
+    LIBRARIES
+        ${AIRSPY_LIBS}
+)
diff --git a/Changelog.txt b/Changelog.txt
new file mode 100644
index 0000000..94a1e46
--- /dev/null
+++ b/Changelog.txt
@@ -0,0 +1,4 @@
+Release 0.1.0 (2016-09-01)
+==========================
+
+- Initial release of Soapy Airspy support module
diff --git a/FindLibAIRSPY.cmake b/FindLibAIRSPY.cmake
new file mode 100644
index 0000000..221edcc
--- /dev/null
+++ b/FindLibAIRSPY.cmake
@@ -0,0 +1,24 @@
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(PC_LIBAIRSPY libairspy)
+
+FIND_PATH(
+    LIBAIRSPY_INCLUDE_DIRS
+    NAMES libairspy/airspy.h
+    HINTS $ENV{LIBAIRSPY_DIR}/include
+        ${PC_LIBAIRSPY_INCLUDEDIR}
+    PATHS /usr/local/include
+          /usr/include
+)
+
+FIND_LIBRARY(
+    LIBAIRSPY_LIBRARIES
+    NAMES airspy
+    HINTS $ENV{LIBAIRSPY_DIR}/lib
+        ${PC_LIBAIRSPY_LIBDIR}
+    PATHS /usr/local/lib
+          /usr/lib
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBAIRSPY DEFAULT_MSG LIBAIRSPY_LIBRARIES LIBAIRSPY_INCLUDE_DIRS)
+MARK_AS_ADVANCED(LIBAIRSPY_LIBRARIES LIBAIRSPY_INCLUDE_DIRS)
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..b8e4a51
--- /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.
diff --git a/LibFindMacros.cmake b/LibFindMacros.cmake
new file mode 100644
index 0000000..69975c5
--- /dev/null
+++ b/LibFindMacros.cmake
@@ -0,0 +1,99 @@
+# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
+# used for the current package. For this to work, the first parameter must be the
+# prefix of the current package, then the prefix of the new package etc, which are
+# passed to find_package.
+macro (libfind_package PREFIX)
+  set (LIBFIND_PACKAGE_ARGS ${ARGN})
+  if (${PREFIX}_FIND_QUIETLY)
+    set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
+  endif (${PREFIX}_FIND_QUIETLY)
+  if (${PREFIX}_FIND_REQUIRED)
+    set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
+  endif (${PREFIX}_FIND_REQUIRED)
+  find_package(${LIBFIND_PACKAGE_ARGS})
+endmacro (libfind_package)
+
+# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
+# where they added pkg_check_modules. Consequently I need to support both in my scripts
+# to avoid those deprecated warnings. Here's a helper that does just that.
+# Works identically to pkg_check_modules, except that no checks are needed prior to use.
+macro (libfind_pkg_check_modules PREFIX PKGNAME)
+  if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+    include(UsePkgConfig)
+    pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
+  else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+    find_package(PkgConfig)
+    if (PKG_CONFIG_FOUND)
+      pkg_check_modules(${PREFIX} ${PKGNAME})
+    endif (PKG_CONFIG_FOUND)
+  endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+endmacro (libfind_pkg_check_modules)
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+macro (libfind_process PREFIX)
+  # Skip processing if already processed during this run
+  if (NOT ${PREFIX}_FOUND)
+    # Start with the assumption that the library was found
+    set (${PREFIX}_FOUND TRUE)
+
+    # Process all includes and set _FOUND to false if any are missing
+    foreach (i ${${PREFIX}_PROCESS_INCLUDES})
+      if (${i})
+        set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
+        mark_as_advanced(${i})
+      else (${i})
+        set (${PREFIX}_FOUND FALSE)
+      endif (${i})
+    endforeach (i)
+
+    # Process all libraries and set _FOUND to false if any are missing
+    foreach (i ${${PREFIX}_PROCESS_LIBS})
+      if (${i})
+        set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
+        mark_as_advanced(${i})
+      else (${i})
+        set (${PREFIX}_FOUND FALSE)
+      endif (${i})
+    endforeach (i)
+
+    # Print message and/or exit on fatal error
+    if (${PREFIX}_FOUND)
+      if (NOT ${PREFIX}_FIND_QUIETLY)
+        message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+      endif (NOT ${PREFIX}_FIND_QUIETLY)
+    else (${PREFIX}_FOUND)
+      if (${PREFIX}_FIND_REQUIRED)
+        foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
+          message("${i}=${${i}}")
+        endforeach (i)
+        message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
+      endif (${PREFIX}_FIND_REQUIRED)
+    endif (${PREFIX}_FOUND)
+  endif (NOT ${PREFIX}_FOUND)
+endmacro (libfind_process)
+
+macro(libfind_library PREFIX basename)
+  set(TMP "")
+  if(MSVC80)
+    set(TMP -vc80)
+  endif(MSVC80)
+  if(MSVC90)
+    set(TMP -vc90)
+  endif(MSVC90)
+  set(${PREFIX}_LIBNAMES ${basename}${TMP})
+  if(${ARGC} GREATER 2)
+    set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
+    string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
+    set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
+  endif(${ARGC} GREATER 2)
+  find_library(${PREFIX}_LIBRARY
+    NAMES ${${PREFIX}_LIBNAMES}
+    PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
+  )
+endmacro(libfind_library)
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6c20162
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# Soapy SDR plugin for Airspy
+
+##Dependencies
+
+* SoapySDR - https://github.com/pothosware/SoapySDR/wiki
+* libairspy - https://github.com/airspy/host/wiki
+
+##Documentation
+
+* https://github.com/pothosware/SoapyAirspy/wiki
diff --git a/Registation.cpp b/Registation.cpp
new file mode 100644
index 0000000..c6a4c5e
--- /dev/null
+++ b/Registation.cpp
@@ -0,0 +1,146 @@
+/*
+ * 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 "SoapyAirspy.hpp"
+#include <SoapySDR/Registry.hpp>
+#include <cstdlib> //malloc
+#include <algorithm>
+
+static std::vector<SoapySDR::Kwargs> findAirspy(const SoapySDR::Kwargs &args)
+{
+    std::vector<SoapySDR::Kwargs> results;
+    
+    airspy_lib_version_t asVersion;
+    airspy_lib_version(&asVersion);
+    
+    // SoapySDR_setLogLevel(SOAPY_SDR_DEBUG);
+    
+    SoapySDR_logf(SOAPY_SDR_DEBUG, "AirSpy Lib v%d.%d rev %d", asVersion.major_version, asVersion.minor_version, asVersion.revision);
+
+    int numDevices = 0;
+   
+    std::vector< struct airspy_device * > foundDevices;
+   
+    int status = 0;
+   
+    // if (args.count("serial") != 0) {
+    //     std::stringstream serialstr;
+    //
+    //     uint32_t serialNum[2];
+    //     std::string serial_in(args.at("serial"));
+    //     std::replace( serial_in.begin(), serial_in.end(), ':', ' ');
+    //     serialstr.str(serial_in);
+    //     serialstr << std::hex;
+    //     serialstr >> serialNum[0];
+    //     serialstr >> serialNum[1];
+    //
+    //     uint64_t serial64 = ((uint64_t) serialNum[0] << 32) | serialNum[1]);
+    //
+    //     SoapySDR_logf(SOAPY_SDR_DEBUG, "Serial? '%s' %u %u 64: %llu", serialstr.str().c_str(), serialNum[0], serialNum[1], serial64);
+    //
+    //     struct airspy_device *searchDev = nullptr;
+    //     status = airspy_open_sn(&searchDev, serial64);
+    //
+    //     SoapySDR_logf(SOAPY_SDR_DEBUG, "Search done..");
+    //
+    //     if (status == AIRSPY_SUCCESS) {
+    //         foundDevices.push_back(searchDev);
+    //     } else {
+    //         SoapySDR_logf(SOAPY_SDR_DEBUG, "Error finding by serial..");
+    //     }
+    // } else
+    {    
+        for (int i = 0, iMax = MAX_DEVICES; i < iMax; i++) {
+            struct airspy_device *searchDev = nullptr;
+            status = airspy_open(&searchDev);
+        
+            if (status != AIRSPY_SUCCESS) {
+                break;
+            }
+        
+            foundDevices.push_back(searchDev);
+        }
+    }
+   
+    SoapySDR_logf(SOAPY_SDR_DEBUG, "%d AirSpy boards found.", foundDevices.size());
+    int devId = 0;
+    
+    for (std::vector< struct airspy_device * >::iterator i = foundDevices.begin(); i != foundDevices.end(); i++) {
+        uint8_t id = AIRSPY_BOARD_ID_INVALID;
+        airspy_read_partid_serialno_t serial;
+        
+        status = airspy_board_id_read(*i, &id);
+		if (status != AIRSPY_SUCCESS) {
+            continue;
+		}
+        
+		status = airspy_board_partid_serialno_read(*i, &serial);
+		if (status != AIRSPY_SUCCESS) {
+			continue;
+		}
+
+        std::string boardName(airspy_board_id_name((enum airspy_board_id)id));
+        std::stringstream serialstr;
+        
+        serialstr.str("");
+        serialstr << std::hex << serial.serial_no[2] << ":" << serial.serial_no[3];
+        
+        SoapySDR_logf(SOAPY_SDR_DEBUG, "Serial %s", serialstr.str().c_str());        
+
+        SoapySDR::Kwargs soapyInfo;
+
+        soapyInfo["device_id"] = std::to_string(devId);
+        soapyInfo["label"] = boardName + " [" + serialstr.str() + "]";
+        soapyInfo["serial"] = serialstr.str();
+        devId++;
+                
+        // if (args.count("serial") != 0) {
+        //     if (args.at("serial") != soapyInfo.at("serial")) {
+        //         continue;
+        //     }
+        //     SoapySDR_logf(SOAPY_SDR_DEBUG, "Found device by serial %s", soapyInfo.at("serial").c_str());
+        // } else
+        if (args.count("device_id") != 0) {
+            if (args.at("device_id") != soapyInfo.at("device_id")) {
+                continue;
+            }
+            SoapySDR_logf(SOAPY_SDR_DEBUG, "Found device by device_id %s", soapyInfo.at("device_id").c_str());
+        }
+        
+        results.push_back(soapyInfo);
+    }
+   
+    for (std::vector< struct airspy_device * >::iterator i = foundDevices.begin(); i != foundDevices.end(); i++) {
+        airspy_close(*i);
+    }
+
+    return results;
+}
+
+static SoapySDR::Device *makeAirspy(const SoapySDR::Kwargs &args)
+{
+    return new SoapyAirspy(args);
+}
+
+static SoapySDR::Registry registerAirspy("airspy", &findAirspy, &makeAirspy, SOAPY_SDR_ABI_VERSION);
diff --git a/Settings.cpp b/Settings.cpp
new file mode 100644
index 0000000..f47f2d1
--- /dev/null
+++ b/Settings.cpp
@@ -0,0 +1,410 @@
+/*
+ * 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 "SoapyAirspy.hpp"
+
+SoapyAirspy::SoapyAirspy(const SoapySDR::Kwargs &args)
+{
+    deviceId = -1;
+
+    sampleRate = 3000000;
+    centerFrequency = 0;
+
+    numBuffers = DEFAULT_NUM_BUFFERS;
+
+    agcMode = false;
+    rfBias = false;
+
+    bufferedElems = 0;
+    resetBuffer = false;
+    
+    streamActive = false;
+    sampleRateChanged.store(false);
+    
+    dev = nullptr;
+    
+    lnaGain = mixerGain = vgaGain = 0;
+    
+    if (args.count("device_id") != 0)
+    {
+        try {
+            deviceId = std::stoi(args.at("device_id"));
+        } catch (const std::invalid_argument &) {
+            throw std::runtime_error("device_id invalid.");
+        }
+        
+        std::vector<struct airspy_device *> allDevs;
+        
+        int status;
+        for (int i = 0, iMax = deviceId; i <= iMax; i++) {
+            struct airspy_device *searchDev = nullptr;
+            status = airspy_open(&searchDev);
+    
+            if (status != AIRSPY_SUCCESS) {
+                continue;
+            }
+    
+            allDevs.push_back(searchDev);
+        }
+
+        int numDevices = allDevs.size();
+
+        if (deviceId < 0 || deviceId >= numDevices) {
+            for (std::vector< struct airspy_device * >::iterator i = allDevs.begin(); i != allDevs.end(); i++) {
+                airspy_close(*i);
+            }
+
+            throw std::runtime_error("Airspy device_id out of range [0 .. " + std::to_string(numDevices) + "].");
+        }
+
+        dev = allDevs[deviceId];
+   
+        for (std::vector< struct airspy_device * >::iterator i = allDevs.begin(); i != allDevs.end(); i++) {
+            if (*i != dev) {
+                airspy_close(*i);
+            }
+        }
+                          
+        SoapySDR_logf(SOAPY_SDR_DEBUG, "Found Airspy device using 'device_id' = %d", deviceId);
+    }
+    
+    if (deviceId == -1) {
+        throw std::runtime_error("device_id missing.");
+    }
+}
+
+SoapyAirspy::~SoapyAirspy(void)
+{
+    airspy_close(dev);
+}
+
+/*******************************************************************
+ * Identification API
+ ******************************************************************/
+
+std::string SoapyAirspy::getDriverKey(void) const
+{
+    return "Airspy";
+}
+
+std::string SoapyAirspy::getHardwareKey(void) const
+{
+    return "Airspy";
+}
+
+SoapySDR::Kwargs SoapyAirspy::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/SoapyAirspy";
+    args["device_id"] = std::to_string(deviceId);
+
+    return args;
+}
+
+/*******************************************************************
+ * Channels API
+ ******************************************************************/
+
+size_t SoapyAirspy::getNumChannels(const int dir) const
+{
+    return (dir == SOAPY_SDR_RX) ? 1 : 0;
+}
+
+/*******************************************************************
+ * Antenna API
+ ******************************************************************/
+
+std::vector<std::string> SoapyAirspy::listAntennas(const int direction, const size_t channel) const
+{
+    std::vector<std::string> antennas;
+    antennas.push_back("RX");
+    return antennas;
+}
+
+void SoapyAirspy::setAntenna(const int direction, const size_t channel, const std::string &name)
+{
+    // TODO
+}
+
+std::string SoapyAirspy::getAntenna(const int direction, const size_t channel) const
+{
+    return "RX";
+}
+
+/*******************************************************************
+ * Frontend corrections API
+ ******************************************************************/
+
+bool SoapyAirspy::hasDCOffsetMode(const int direction, const size_t channel) const
+{
+    return false;
+}
+
+/*******************************************************************
+ * Gain API
+ ******************************************************************/
+
+std::vector<std::string> SoapyAirspy::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;
+
+    results.push_back("LNA");
+    results.push_back("MIX");
+    results.push_back("VGA");
+
+    return results;
+}
+
+bool SoapyAirspy::hasGainMode(const int direction, const size_t channel) const
+{
+    return true;
+}
+
+void SoapyAirspy::setGainMode(const int direction, const size_t channel, const bool automatic)
+{
+    agcMode = automatic;
+    
+    airspy_set_lna_agc(dev, agcMode?1:0);
+    airspy_set_mixer_agc(dev, agcMode?1:0);
+    
+    SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting AGC: %s", automatic ? "Automatic" : "Manual");
+}
+
+bool SoapyAirspy::getGainMode(const int direction, const size_t channel) const
+{
+    return agcMode;
+}
+
+void SoapyAirspy::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 SoapyAirspy::setGain(const int direction, const size_t channel, const std::string &name, const double value)
+{
+    if (name == "LNA")
+    {
+        lnaGain = uint8_t(value);
+        airspy_set_lna_gain(dev, lnaGain);
+    }
+    else if (name == "MIX")
+    {
+        mixerGain = uint8_t(value);
+        airspy_set_mixer_gain(dev, mixerGain);
+    }
+    else if (name == "VGA")
+    {
+        vgaGain = uint8_t(value);
+        airspy_set_vga_gain(dev, vgaGain);
+    }
+}
+
+double SoapyAirspy::getGain(const int direction, const size_t channel, const std::string &name) const
+{
+    if (name == "LNA")
+    {
+        return lnaGain;
+    }
+    else if (name == "MIX")
+    {
+        return mixerGain;
+    }
+    else if (name == "VGA")
+    {
+        return vgaGain;
+    }
+
+    return 0;
+}
+
+SoapySDR::Range SoapyAirspy::getGainRange(const int direction, const size_t channel, const std::string &name) const
+{
+    if (name == "LNA" || name == "MIX" || name == "VGA") {
+        return SoapySDR::Range(0, 15);
+    }
+ 
+    return SoapySDR::Range(0, 15);    
+}
+
+/*******************************************************************
+ * Frequency API
+ ******************************************************************/
+
+void SoapyAirspy::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);
+        airspy_set_freq(dev, centerFrequency);
+    }
+}
+
+double SoapyAirspy::getFrequency(const int direction, const size_t channel, const std::string &name) const
+{
+    if (name == "RF")
+    {
+        return (double) centerFrequency;
+    }
+
+    return 0;
+}
+
+std::vector<std::string> SoapyAirspy::listFrequencies(const int direction, const size_t channel) const
+{
+    std::vector<std::string> names;
+    names.push_back("RF");
+    return names;
+}
+
+SoapySDR::RangeList SoapyAirspy::getFrequencyRange(
+        const int direction,
+        const size_t channel,
+        const std::string &name) const
+{
+    SoapySDR::RangeList results;
+    if (name == "RF")
+    {
+        results.push_back(SoapySDR::Range(24000000, 1800000000));
+    }
+    return results;
+}
+
+SoapySDR::ArgInfoList SoapyAirspy::getFrequencyArgsInfo(const int direction, const size_t channel) const
+{
+    SoapySDR::ArgInfoList freqArgs;
+
+    // TODO: frequency arguments
+
+    return freqArgs;
+}
+
+/*******************************************************************
+ * Sample Rate API
+ ******************************************************************/
+
+void SoapyAirspy::setSampleRate(const int direction, const size_t channel, const double rate)
+{
+    SoapySDR_logf(SOAPY_SDR_DEBUG, "Setting sample rate: %d", sampleRate);
+
+    if (sampleRate != rate) {
+        sampleRate = rate;
+        resetBuffer = true;
+        sampleRateChanged.store(true);
+    }
+}
+
+double SoapyAirspy::getSampleRate(const int direction, const size_t channel) const
+{
+    return sampleRate;
+}
+
+std::vector<double> SoapyAirspy::listSampleRates(const int direction, const size_t channel) const
+{
+    std::vector<double> results;
+
+    uint32_t numRates;
+	airspy_get_samplerates(dev, &numRates, 0);
+
+	std::vector<uint32_t> samplerates;
+    samplerates.resize(numRates);
+    
+	airspy_get_samplerates(dev, samplerates.data(), numRates);
+
+	for (auto i: samplerates) {
+        results.push_back(i);
+	}
+
+    return results;
+}
+
+void SoapyAirspy::setBandwidth(const int direction, const size_t channel, const double bw)
+{
+    SoapySDR::Device::setBandwidth(direction, channel, bw);
+}
+
+double SoapyAirspy::getBandwidth(const int direction, const size_t channel) const
+{
+    return SoapySDR::Device::getBandwidth(direction, channel);
+}
+
+std::vector<double> SoapyAirspy::listBandwidths(const int direction, const size_t channel) const
+{
+    std::vector<double> results;
+
+    return results;
+}
+
+/*******************************************************************
+ * Settings API
+ ******************************************************************/
+
+SoapySDR::ArgInfoList SoapyAirspy::getSettingInfo(void) const
+{
+    SoapySDR::ArgInfoList setArgs;
+ 
+    // Bias-T
+    SoapySDR::ArgInfo biasOffsetArg;
+    biasOffsetArg.key = "biastee";
+    biasOffsetArg.value = "false";
+    biasOffsetArg.name = "Bias tee";
+    biasOffsetArg.description = "Enable the 4.5v DC Bias tee to power SpyVerter / LNA / etc. via antenna connection.";
+    biasOffsetArg.type = SoapySDR::ArgInfo::BOOL;
+   
+    setArgs.push_back(biasOffsetArg);
+ 
+    return setArgs;
+}
+
+void SoapyAirspy::writeSetting(const std::string &key, const std::string &value)
+{
+    if (key == "biastee") {
+        bool enable = (value == "true");
+
+        airspy_set_rf_bias(dev, enable);
+    }
+}
+
+std::string SoapyAirspy::readSetting(const std::string &key) const
+{
+    if (key == "biastee") {
+        return rfBias?"true":"false";
+    }
+    
+    // SoapySDR_logf(SOAPY_SDR_WARNING, "Unknown setting '%s'", key.c_str());
+    return "";
+}
diff --git a/SoapyAirspy.hpp b/SoapyAirspy.hpp
new file mode 100644
index 0000000..96e6289
--- /dev/null
+++ b/SoapyAirspy.hpp
@@ -0,0 +1,237 @@
+/*
+ * 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 <stdexcept>
+#include <thread>
+#include <mutex>
+#include <atomic>
+#include <condition_variable>
+#include <string>
+#include <cstring>
+#include <algorithm>
+
+#include <libairspy/airspy.h>
+
+#define DEFAULT_BUFFER_LENGTH 2048
+#define DEFAULT_NUM_BUFFERS 6
+#define MAX_DEVICES 32
+
+class SoapyAirspy: public SoapySDR::Device
+{
+public:
+    SoapyAirspy(const SoapySDR::Kwargs &args);
+
+    ~SoapyAirspy(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
+     ******************************************************************/
+
+    /*******************************************************************
+     * 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;
+    struct airspy_device *dev;
+
+    //cached settings
+    uint32_t sampleRate, centerFrequency;
+    unsigned int bufferLength;
+    size_t numBuffers;
+    bool agcMode, streamActive, rfBias;
+    std::atomic_bool sampleRateChanged;
+    int elementsPerSample;
+    airspy_sample_type asFormat;
+    uint8_t lnaGain, mixerGain, vgaGain;
+    
+public:
+    //async api usage
+    int rx_callback(airspy_transfer *t);
+
+    std::mutex _buf_mutex;
+    std::condition_variable _buf_cond;
+
+    std::vector<std::vector<float> > _buffs;
+    size_t	_buf_head;
+    size_t	_buf_tail;
+    size_t	_buf_count;
+    float *_currentBuff;
+    bool _overflowEvent;
+    size_t bufferedElems;
+    size_t _currentHandle;
+    bool resetBuffer;
+};
diff --git a/Streaming.cpp b/Streaming.cpp
new file mode 100644
index 0000000..207df77
--- /dev/null
+++ b/Streaming.cpp
@@ -0,0 +1,337 @@
+/*
+ * 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 "SoapyAirspy.hpp"
+#include <SoapySDR/Logger.hpp>
+#include <algorithm> //min
+#include <climits> //SHRT_MAX
+#include <cstring> // memcpy
+
+
+std::vector<std::string> SoapyAirspy::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 SoapyAirspy::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const {
+     fullScale = 65536;
+     return "CS16";
+}
+
+SoapySDR::ArgInfoList SoapyAirspy::getStreamArgsInfo(const int direction, const size_t channel) const {
+    SoapySDR::ArgInfoList streamArgs;
+
+    // SoapySDR::ArgInfo chanArg;
+    // chanArg.key = "chan";
+    // chanArg.value = "mono_l";
+    // chanArg.name = "Channel Setup";
+    // chanArg.description = "Input channel configuration.";
+    // chanArg.type = SoapySDR::ArgInfo::STRING;
+    // std::vector<std::string> chanOpts;
+    // std::vector<std::string> chanOptNames;
+    // chanOpts.push_back("mono_l");
+    // chanOptNames.push_back("Mono Left");
+    // chanOpts.push_back("mono_r");
+    // chanOptNames.push_back("Mono Right");
+    // chanOpts.push_back("stereo_iq");
+    // chanOptNames.push_back("Complex L/R = I/Q");
+    // chanOpts.push_back("stereo_qi");
+    // chanOptNames.push_back("Complex L/R = Q/I");
+    // chanArg.options = chanOpts;
+    // chanArg.optionNames = chanOptNames;
+    // streamArgs.push_back(chanArg);
+
+    return streamArgs;
+}
+
+/*******************************************************************
+ * Async thread work
+ ******************************************************************/
+
+static int _rx_callback(airspy_transfer *t)
+{
+    //printf("_rx_callback\n");
+    SoapyAirspy *self = (SoapyAirspy *)t->ctx;
+    return self->rx_callback(t);
+}
+
+int SoapyAirspy::rx_callback(airspy_transfer *t)
+{
+    std::unique_lock<std::mutex> lock(_buf_mutex);
+
+    if (sampleRateChanged.load()) {
+        return 1;
+    }
+
+    //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 0;
+    }
+
+    //copy into the buffer queue
+    auto &buff = _buffs[_buf_tail];
+    buff.resize(t->sample_count * elementsPerSample);
+    std::memcpy(buff.data(), t->samples, t->sample_count * elementsPerSample * sizeof(float));
+
+    //increment the tail pointer
+    _buf_tail = (_buf_tail + 1) % numBuffers;
+    _buf_count++;
+
+    //notify readStream()
+    _buf_cond.notify_one();
+
+    return 0;
+}
+
+/*******************************************************************
+ * Stream API
+ ******************************************************************/
+
+SoapySDR::Stream *SoapyAirspy::setupStream(
+        const int direction,
+        const std::string &format,
+        const std::vector<size_t> &channels,
+        const SoapySDR::Kwargs &args)
+{
+    //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");
+    }
+
+    asFormat = AIRSPY_SAMPLE_INT16_IQ;
+
+    //check the format
+    if (format == "CF32") {
+        SoapySDR_log(SOAPY_SDR_INFO, "Using format CF32.");
+        asFormat = AIRSPY_SAMPLE_FLOAT32_IQ;
+    } else if (format == "CS16") {
+        SoapySDR_log(SOAPY_SDR_INFO, "Using format CS16.");
+        asFormat = AIRSPY_SAMPLE_INT16_IQ;
+    } else {
+        throw std::runtime_error(
+                "setupStream invalid format '" + format
+                        + "' -- Only CS16 and CF32 are supported by SoapyAirspy module.");
+    }
+
+    // TODO: use airspy_set_sample_type(dev, asFormat); when INT16 imlemented
+    airspy_set_sample_type(dev, AIRSPY_SAMPLE_FLOAT32_IQ);
+    sampleRateChanged.store(true);
+
+    bufferLength = DEFAULT_BUFFER_LENGTH*2;
+    elementsPerSample = 2;
+
+    //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 SoapyAirspy::closeStream(SoapySDR::Stream *stream)
+{
+    _buffs.clear();
+}
+
+size_t SoapyAirspy::getStreamMTU(SoapySDR::Stream *stream) const
+{
+    return bufferLength / elementsPerSample;
+}
+
+int SoapyAirspy::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;
+    
+    if (sampleRateChanged.load()) {
+        airspy_set_samplerate(dev, sampleRate);
+        sampleRateChanged.store(false);
+    }
+    airspy_start_rx(dev, &_rx_callback, (void *) this);
+    
+    return 0;
+}
+
+int SoapyAirspy::deactivateStream(SoapySDR::Stream *stream, const int flags, const long long timeNs)
+{
+    if (flags != 0) return SOAPY_SDR_NOT_SUPPORTED;
+
+    airspy_stop_rx(dev);
+    
+    streamActive = false;
+    
+    return 0;
+}
+
+int SoapyAirspy::readStream(
+        SoapySDR::Stream *stream,
+        void * const *buffs,
+        const size_t numElems,
+        int &flags,
+        long long &timeNs,
+        const long timeoutUs)
+{    
+    if (!airspy_is_streaming(dev)) {
+        return 0;
+    }
+    
+    if (sampleRateChanged.load()) {
+        airspy_stop_rx(dev);
+        airspy_set_samplerate(dev, sampleRate);
+        airspy_start_rx(dev, &_rx_callback, (void *) this);
+        sampleRateChanged.store(false);
+    }
+
+    //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 (asFormat == AIRSPY_SAMPLE_FLOAT32_IQ)
+    {
+        std::memcpy(buff0, _currentBuff, returnedElems * 2 * sizeof(float) );
+    }
+    else if (asFormat == AIRSPY_SAMPLE_INT16_IQ)    // TODO: use actual airspy int samples
+    {
+        int16_t *itarget = (int16_t *) buff0;
+        std::complex<int16_t> tmp;
+        for (size_t i = 0; i < returnedElems; i++)
+        {
+            itarget[i * 2] = int16_t(_currentBuff[i * 2] * 32767.0);
+            itarget[i * 2 + 1] = int16_t(_currentBuff[i * 2 + 1] * 32767.0);
+        }
+    }
+    
+    //bump variables for next call into readStream
+    bufferedElems -= returnedElems;
+    _currentBuff += returnedElems * elementsPerSample;
+
+    //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 SoapyAirspy::getNumDirectAccessBuffers(SoapySDR::Stream *stream)
+{
+    return _buffs.size();
+}
+
+int SoapyAirspy::getDirectAccessBufferAddrs(SoapySDR::Stream *stream, const size_t handle, void **buffs)
+{
+    buffs[0] = (void *)_buffs[handle].data();
+    return 0;
+}
+
+int SoapyAirspy::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() / elementsPerSample;
+}
+
+void SoapyAirspy::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..f498940
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+soapyairspy (0.1.0) unstable; urgency=low
+
+  * Release 0.1.1 (2016-09-01)
+
+ -- Josh Blum <josh at pothosware.com>  Thu, 01 Sep 2016 17:23:53 -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..9757abd
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,30 @@
+Source: soapyairspy
+Section: hamradio
+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,
+    libairspy-dev
+Standards-Version: 3.9.8
+Homepage: https://github.com/pothosware/SoapyAirspy/wiki
+Vcs-Git: https://github.com/pothosware/SoapyAirspy.git
+Vcs-Browser: https://github.com/pothosware/SoapyAirspy
+
+Package: soapysdr0.5-2-module-airspy
+Architecture: any
+Multi-Arch: same
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Airspy device support for SoapySDR
+ The Soapy Airspy project provides a SoapySDR hardware support module.
+
+Package: soapysdr-module-airspy
+Architecture: all
+Depends: soapysdr0.5-2-module-airspy, ${misc:Depends}
+Description: Airspy device support for SoapySDR (default version)
+ The Soapy Airspy project provides a SoapySDR hardware support module.
+ .
+ This is an empty dependency package that pulls in the Airspy module
+ for the default version of libsoapysdr.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..9aa0c36
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,24 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: soapyairspy
+Source: https://github.com/pothosware/SoapyAirspy/wiki
+
+Files: *
+Copyright: Copyright (c) 2016 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 100755
index 0000000..de8f7cc
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,16 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+	dh $@ --buildsystem=cmake --parallel
+
+override_dh_auto_configure:
+	dh_auto_configure -- -DLIB_SUFFIX="/$(DEB_HOST_MULTIARCH)"
+
+override_dh_installchangelogs:
+	dh_installchangelogs Changelog.txt
diff --git a/debian/soapysdr0.5-2-module-airspy.install b/debian/soapysdr0.5-2-module-airspy.install
new file mode 100644
index 0000000..f1d0181
--- /dev/null
+++ b/debian/soapysdr0.5-2-module-airspy.install
@@ -0,0 +1 @@
+usr/lib/*
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/soapyairspy.git



More information about the pkg-hamradio-commits mailing list