[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