[hamradio-commits] [soapyhackrf] 01/02: New upstream version 0.2.1+git20160919

Andreas E. Bombe aeb at moszumanska.debian.org
Sat Sep 24 11:09:29 UTC 2016


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

aeb pushed a commit to branch master
in repository soapyhackrf.

commit b7eb359ee6269c15971056735b840182f14cd700
Author: Andreas Bombe <aeb at debian.org>
Date:   Wed Sep 21 21:11:20 2016 +0200

    New upstream version 0.2.1+git20160919
---
 .travis.yml                                |  56 ++
 CMakeLists.txt                             |  55 ++
 Changelog.txt                              |  29 +
 FindLIBHACKRF.cmake                        |  55 ++
 HackRF_Registation.cpp                     |  94 ++++
 HackRF_Session.cpp                         |  58 ++
 HackRF_Settings.cpp                        | 744 +++++++++++++++++++++++++
 HackRF_Streaming.cpp                       | 834 +++++++++++++++++++++++++++++
 LICENSE                                    |  22 +
 README.md                                  |  38 ++
 SoapyHackRF.hpp                            | 374 +++++++++++++
 debian/changelog                           |  17 +
 debian/compat                              |   1 +
 debian/control                             |  30 ++
 debian/copyright                           |  26 +
 debian/docs                                |   1 +
 debian/rules                               |  17 +
 debian/soapysdr0.5-2-module-hackrf.install |   1 +
 debian/source/format                       |   1 +
 self_test.py                               |  81 +++
 20 files changed, 2534 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2234626
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,56 @@
+########################################################################
+## Travis CI config for SoapyHackRF
+##
+## * installs hackrf from PPA
+## * installs SoapySDR from source
+## * confirms build and install
+## * checks that drivers load
+########################################################################
+
+sudo: required
+dist: trusty
+
+language: cpp
+compiler: gcc
+
+env:
+  global:
+    - INSTALL_PREFIX=/usr/local
+    - SOAPY_SDR_BRANCH=master
+  matrix:
+    - BUILD_TYPE=Debug
+    - BUILD_TYPE=Release
+
+before_install:
+  # regular ubuntu packages
+  - sudo add-apt-repository main
+  - sudo add-apt-repository universe
+
+  # driver development files from ppa
+  - sudo add-apt-repository -y ppa:myriadrf/drivers
+
+  # update after package changes
+  - sudo apt-get update
+
+install:
+  #sdr development files
+  - sudo apt-get install --no-install-recommends -q -y libhackrf-dev
+
+  # install SoapySDR from source
+  - git clone https://github.com/pothosware/SoapySDR.git
+  - pushd SoapySDR
+  - git checkout ${SOAPY_SDR_BRANCH}
+  - mkdir build && cd build
+  - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_PYTHON=OFF -DENABLE_PYTHON3=OFF
+  - make && sudo make install
+  - popd
+
+script:
+  - mkdir build && cd build
+  - cmake ../ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
+  - make && sudo make install
+  # print info about the install
+  - export LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH}
+  - export PATH=${INSTALL_PREFIX}/bin:${PATH}
+  - SoapySDRUtil --info
+  - SoapySDRUtil --check=hackrf
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..8590d90
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,55 @@
+######################################################################## 
+ # Build Soapy SDR support module for HackRF
+ ######################################################################## 
+
+cmake_minimum_required(VERSION 2.8.7)
+project(SoapyHackRF CXX)
+
+find_package(SoapySDR "0.4.0" NO_MODULE)
+ 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(LIBHACKRF)
+
+if (NOT LIBHACKRF_FOUND) 
+     message(FATAL_ERROR "HackRF development files not found...") 
+endif () 
+message(STATUS "LIBHACKRF_INCLUDE_DIR - ${LIBHACKRF_INCLUDE_DIR}")
+message(STATUS "LIBHACKRF_LIBRARIES - ${LIBHACKRF_LIBRARIES}")
+
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${LIBHACKRF_INCLUDE_DIR})
+
+#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()
+
+    #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)
+
+SOAPY_SDR_MODULE_UTIL(
+    TARGET HackRFSupport
+    SOURCES
+	HackRF_Registation.cpp
+	HackRF_Settings.cpp
+	HackRF_Streaming.cpp
+	HackRF_Session.cpp
+    LIBRARIES ${LIBHACKRF_LIBRARIES}
+)
diff --git a/Changelog.txt b/Changelog.txt
new file mode 100644
index 0000000..dba3990
--- /dev/null
+++ b/Changelog.txt
@@ -0,0 +1,29 @@
+Release 0.2.2 (pending)
+==========================
+
+- Clarified copyright statements in source files
+- Update debian files for SoapySDR module ABI format
+
+Release 0.2.1 (2016-02-29)
+==========================
+
+- Fixed debian control file Maintainer/Uploaders
+- Reset buffer counters before activating RX stream
+- Rx stream switching waits for tx to be consumed
+
+Release 0.2.0 (2015-11-20)
+==========================
+
+- Implemented Tx/Rx automatic stream switching
+- Implemented automatic gain distribution algorithm
+- Implemented the direct buffer access API
+- Implemented getStreamFormats() for SoapySDR v0.4
+- Implemented getNativeStreamFormat() for SoapySDR v0.4
+- Implemented getStreamArgsInfo() for SoapySDR v0.4
+- Created settings API calls for Bias TX control
+- Moved buffers device arg into stream args
+
+Release 0.1.0 (2015-10-10)
+==========================
+
+- First release of SoapyHackRF support module
diff --git a/FindLIBHACKRF.cmake b/FindLIBHACKRF.cmake
new file mode 100644
index 0000000..a97fec5
--- /dev/null
+++ b/FindLIBHACKRF.cmake
@@ -0,0 +1,55 @@
+# - Try to find the libhackrf library
+# Once done this defines
+#
+#  LIBHACKRF_FOUND - system has libhackrf
+#  LIBHACKRF_INCLUDE_DIR - the libhackrf include directory
+#  LIBHACKRF_LIBRARIES - Link these to use libhackrf
+
+# Copyright (c) 2013  Benjamin Vernoux
+#
+
+
+if (LIBHACKRF_INCLUDE_DIR AND LIBHACKRF_LIBRARIES)
+
+  # in cache already
+  set(LIBHACKRF_FOUND TRUE)
+
+else (LIBHACKRF_INCLUDE_DIR AND LIBHACKRF_LIBRARIES)
+  IF (NOT WIN32)
+    # use pkg-config to get the directories and then use these values
+    # in the FIND_PATH() and FIND_LIBRARY() calls
+    find_package(PkgConfig)
+    pkg_check_modules(PC_LIBHACKRF QUIET libhackrf)
+  ENDIF(NOT WIN32)
+
+  FIND_PATH(LIBHACKRF_INCLUDE_DIR
+    NAMES hackrf.h
+    HINTS $ENV{LIBHACKRF_DIR}/include ${PC_LIBHACKRF_INCLUDEDIR}
+    PATHS /usr/local/include/libhackrf /usr/include/libhackrf /usr/local/include
+    /usr/include ${CMAKE_SOURCE_DIR}/../libhackrf/src
+    /opt/local/include/libhackrf
+    ${LIBHACKRF_INCLUDE_DIR}
+  )
+
+  set(libhackrf_library_names hackrf)
+
+  FIND_LIBRARY(LIBHACKRF_LIBRARIES
+    NAMES ${libhackrf_library_names}
+    HINTS $ENV{LIBHACKRF_DIR}/lib ${PC_LIBHACKRF_LIBDIR}
+    PATHS /usr/local/lib /usr/lib /opt/local/lib ${PC_LIBHACKRF_LIBDIR} ${PC_LIBHACKRF_LIBRARY_DIRS} ${CMAKE_SOURCE_DIR}/../libhackrf/src
+  )
+
+  if(LIBHACKRF_INCLUDE_DIR)
+    set(CMAKE_REQUIRED_INCLUDES ${LIBHACKRF_INCLUDE_DIR})
+  endif()
+
+  if(LIBHACKRF_LIBRARIES)
+    set(CMAKE_REQUIRED_LIBRARIES ${LIBHACKRF_LIBRARIES})
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBHACKRF DEFAULT_MSG LIBHACKRF_LIBRARIES LIBHACKRF_INCLUDE_DIR)
+
+  MARK_AS_ADVANCED(LIBHACKRF_INCLUDE_DIR LIBHACKRF_LIBRARIES)
+
+endif (LIBHACKRF_INCLUDE_DIR AND LIBHACKRF_LIBRARIES)
\ No newline at end of file
diff --git a/HackRF_Registation.cpp b/HackRF_Registation.cpp
new file mode 100644
index 0000000..e69f02b
--- /dev/null
+++ b/HackRF_Registation.cpp
@@ -0,0 +1,94 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Wei Jiang
+ * 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 "SoapyHackRF.hpp"
+#include <SoapySDR/Registry.hpp>
+
+
+
+static std::vector<SoapySDR::Kwargs> find_HackRF(const SoapySDR::Kwargs &args)
+{
+	SoapyHackRFSession Sess;
+
+	std::vector<SoapySDR::Kwargs> results;
+
+	hackrf_device_list_t *list;
+
+	list =hackrf_device_list();
+
+	if (list->devicecount > 0) {
+	
+		for (int i = 0; i < list->devicecount; i++) {
+		
+			hackrf_device* device = NULL;
+			uint8_t board_id = BOARD_ID_INVALID;
+			read_partid_serialno_t read_partid_serialno;
+
+			hackrf_device_list_open(list, i, &device);
+
+			SoapySDR::Kwargs options;
+
+			if (device!=NULL) {
+
+				hackrf_board_id_read(device, &board_id);
+
+				options["device"] = hackrf_board_id_name((hackrf_board_id) board_id);
+
+				char version_str[100];
+
+				hackrf_version_string_read(device, &version_str[0], 100);
+
+				options["version"] = version_str;
+
+				hackrf_board_partid_serialno_read(device, &read_partid_serialno);
+
+				char part_id_str[100];
+
+				sprintf(part_id_str, "%08x%08x", read_partid_serialno.part_id[0], read_partid_serialno.part_id[1]);
+
+				options["part_id"] = part_id_str;
+
+				char serial_str[100];
+				sprintf(serial_str, "%08x%08x%08x%08x", read_partid_serialno.serial_no[0],
+						read_partid_serialno.serial_no[1], read_partid_serialno.serial_no[2],
+						read_partid_serialno.serial_no[3]);
+				options["serial"] = serial_str;
+
+				results.push_back(options);
+
+				hackrf_close(device);
+			}
+		
+		}
+	
+	}
+
+	hackrf_device_list_free(list);
+
+	return results;
+}
+
+static SoapySDR::Device *make_HackRF(const SoapySDR::Kwargs &args)
+{
+    return new SoapyHackRF(args);
+}
+
+static SoapySDR::Registry register_hackrf("hackrf", &find_HackRF, &make_HackRF, SOAPY_SDR_ABI_VERSION);
diff --git a/HackRF_Session.cpp b/HackRF_Session.cpp
new file mode 100644
index 0000000..1ce0a9b
--- /dev/null
+++ b/HackRF_Session.cpp
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josh Blum
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SoapyHackRF.hpp"
+#include <SoapySDR/Logger.hpp>
+#include <mutex>
+#include <cstddef>
+
+static std::mutex sessionMutex;
+static size_t sessionCount = 0;
+
+SoapyHackRFSession::SoapyHackRFSession(void)
+{
+    std::lock_guard<std::mutex> lock(sessionMutex);
+
+    if (sessionCount == 0)
+    {
+        int ret = hackrf_init();
+        if (ret != HACKRF_SUCCESS)
+        {
+            SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_init() failed -- %s", hackrf_error_name(hackrf_error(ret)));
+        }
+    }
+    sessionCount++;
+}
+
+SoapyHackRFSession::~SoapyHackRFSession(void)
+{
+    std::lock_guard<std::mutex> lock(sessionMutex);
+
+    sessionCount--;
+    if (sessionCount == 0)
+    {
+        int ret = hackrf_exit();
+        if (ret != HACKRF_SUCCESS)
+        {
+            SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_exit() failed -- %s", hackrf_error_name(hackrf_error(ret)));
+        }
+    }
+}
diff --git a/HackRF_Settings.cpp b/HackRF_Settings.cpp
new file mode 100644
index 0000000..b929e25
--- /dev/null
+++ b/HackRF_Settings.cpp
@@ -0,0 +1,744 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2016 Wei Jiang
+ * 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 "SoapyHackRF.hpp"
+
+
+SoapyHackRF::SoapyHackRF( const SoapySDR::Kwargs &args )
+{
+	std::string argsStr;
+	for (const auto &pair : args)
+	{
+		if (not argsStr.empty()) argsStr += ", ";
+		argsStr += pair.first + "=" + pair.second;
+	}
+	SoapySDR_logf( SOAPY_SDR_INFO, "Opening HackRF device instance {%s}...", argsStr.c_str());
+
+	_rx_stream=new RXStream();
+
+	_rx_stream->remainderSamps=0;
+	_rx_stream->remainderOffset=0;
+	_rx_stream->remainderBuff= nullptr;
+	_rx_stream->remainderHandle=-1;
+	_rx_stream->vga_gain=16;
+	_rx_stream->lna_gain=16;
+	_rx_stream->amp_gain=0;
+	_rx_stream->frequecy=0;
+	_rx_stream->samplerate=0;
+	_rx_stream->bandwidth=0;
+	_rx_stream->format=HACKRF_FORMAT_INT8;
+	_rx_stream->buf_len=BUF_LEN;
+	_rx_stream->buf_num=BUF_NUM;
+	_rx_stream->buf_count=0;
+	_rx_stream->buf_tail=0;
+	_rx_stream->buf_head=0;
+
+	_tx_stream=new TXStream();
+
+	_tx_stream->remainderSamps=0;
+	_tx_stream->remainderOffset=0;
+	_tx_stream->remainderBuff= nullptr;
+	_tx_stream->remainderHandle=-1;
+	_tx_stream->vga_gain=0;
+	_tx_stream->amp_gain=0;
+	_tx_stream->frequecy=0;
+	_tx_stream->samplerate=0;
+	_tx_stream->bandwidth=0;
+	_tx_stream->format=HACKRF_FORMAT_INT8;
+	_tx_stream->buf_len=BUF_LEN;
+	_tx_stream->buf_num=BUF_NUM;
+	_tx_stream->buf_count=0;
+	_tx_stream->buf_tail=0;
+	_tx_stream->buf_head=0;
+	_tx_stream->burst_samps=0;
+	_tx_stream->burst_end=false;
+
+	_current_mode=TRANSCEIVER_MODE_OFF;
+
+	_auto_bandwidth=true;
+
+	_dev		= nullptr;
+
+	_list= nullptr;
+
+	_current_amp = 0;
+
+	_current_frequency = 0;
+
+	_current_samplerate = 0;
+
+	_current_bandwidth=0;
+
+	_id = -1;
+
+
+	_list= hackrf_device_list();
+
+	if ( args.count( "hackrf" ) != 0 )
+	{
+		_id = std::stoi( args.at( "hackrf" ) );
+
+		if ( _id < 0 && _id > _list->devicecount )
+		{
+			throw std::runtime_error( "hackrf out of range [0 .. " + std::to_string( _list->devicecount ) + "]." );
+		}
+		int ret = hackrf_device_list_open(_list, _id, &_dev );
+		if ( ret != HACKRF_SUCCESS )
+		{
+			hackrf_device_list_free(_list);
+			SoapySDR_logf( SOAPY_SDR_INFO, "Could not Open HackRF Device by Index:%d", _id );
+			throw std::runtime_error("hackrf open failed");
+		}
+	} else if ( _id == -1 )
+	{
+		int ret = hackrf_open( &_dev );
+		if ( ret != HACKRF_SUCCESS )
+		{
+			SoapySDR_logf( SOAPY_SDR_INFO, "Could not Open HackRF Device" );
+			throw std::runtime_error("hackrf open failed");
+		}
+	}
+
+
+
+}
+
+
+SoapyHackRF::~SoapyHackRF( void )
+{
+	if ( _dev )
+	{
+		hackrf_device_list_free(_list);
+		hackrf_close( _dev );
+	}
+
+
+	if (_rx_stream){
+
+
+		if ( _rx_stream->buf )
+		{
+			for ( unsigned int i = 0; i < _rx_stream->buf_num; ++i )
+			{
+				if ( _rx_stream->buf[i] )
+				{
+					free( _rx_stream->buf[i] );
+				}
+			}
+			free( _rx_stream->buf );
+			_rx_stream->buf = NULL;
+		}
+
+		delete _rx_stream;
+	}
+
+
+	if (_tx_stream){
+
+
+		if ( _tx_stream->buf )
+		{
+			for ( unsigned int i = 0; i < _tx_stream->buf_num; ++i )
+			{
+				if ( _tx_stream->buf[i] )
+				{
+					free( _tx_stream->buf[i] );
+				}
+			}
+			free( _tx_stream->buf );
+			_tx_stream->buf = NULL;
+		}
+
+		delete _tx_stream;
+	}
+
+	/* cleanup device handles */
+}
+
+
+/*******************************************************************
+ * Identification API
+ ******************************************************************/
+
+std::string SoapyHackRF::getDriverKey( void ) const
+{
+
+	return("HackRF");
+}
+
+
+std::string SoapyHackRF::getHardwareKey( void ) const
+{
+	uint8_t board_id=BOARD_ID_INVALID;
+
+	hackrf_board_id_read(_dev,&board_id);
+
+	return(hackrf_board_id_name((hackrf_board_id)board_id));
+}
+
+
+SoapySDR::Kwargs SoapyHackRF::getHardwareInfo( void ) const
+{
+	SoapySDR::Kwargs info;
+
+	char version_str[100];
+
+	hackrf_version_string_read(_dev, &version_str[0], 100);
+
+	info["version"] = version_str;
+
+	read_partid_serialno_t read_partid_serialno;
+
+	hackrf_board_partid_serialno_read(_dev, &read_partid_serialno);
+
+	char part_id_str[100];
+
+	sprintf(part_id_str, "%08x%08x", read_partid_serialno.part_id[0], read_partid_serialno.part_id[1]);
+
+	info["part id"] = part_id_str;
+
+	char serial_str[100];
+	sprintf(serial_str, "%08x%08x%08x%08x", read_partid_serialno.serial_no[0], read_partid_serialno.serial_no[1], read_partid_serialno.serial_no[2], read_partid_serialno.serial_no[3]);
+	info["serial"] = serial_str;
+
+	uint16_t clock;
+
+	hackrf_si5351c_read(_dev,0,&clock);
+
+	info["clock source"]=(clock==0x51)?"internal":"external";
+
+	return(info);
+
+}
+
+
+/*******************************************************************
+ * Channels API
+ ******************************************************************/
+
+size_t SoapyHackRF::getNumChannels( const int dir ) const
+{
+	return(1);
+}
+
+
+bool SoapyHackRF::getFullDuplex( const int direction, const size_t channel ) const
+{
+	return(false);
+}
+
+/*******************************************************************
+ * Settings API
+ ******************************************************************/
+
+SoapySDR::ArgInfoList SoapyHackRF::getSettingInfo(void) const
+{
+	SoapySDR::ArgInfoList setArgs;
+
+	SoapySDR::ArgInfo biastxArg;
+	biastxArg.key="bias_tx";
+	biastxArg.value="false";
+	biastxArg.name="Antenna Bias";
+	biastxArg.description="Antenna port power control.";
+	biastxArg.type=SoapySDR::ArgInfo::BOOL;
+	setArgs.push_back(biastxArg);
+
+	return setArgs;
+}
+
+void SoapyHackRF::writeSetting(const std::string &key, const std::string &value)
+{
+	if(key=="bias_tx"){
+		_tx_stream->bias=(value=="true") ? true : false;
+		int ret=hackrf_set_antenna_enable(_dev,_tx_stream->bias);
+		if(ret!=HACKRF_SUCCESS){
+
+			SoapySDR_logf(SOAPY_SDR_INFO,"Failed to apply antenna bias voltage");
+
+		}
+	}
+
+}
+
+std::string SoapyHackRF::readSetting(const std::string &key) const
+{
+	if (key == "bias_tx") {
+		return _tx_stream->bias?"true":"false";
+	}
+	return "";
+}
+/*******************************************************************
+ * Antenna API
+ ******************************************************************/
+
+std::vector<std::string> SoapyHackRF::listAntennas( const int direction, const size_t channel ) const
+{
+	std::vector<std::string> options;
+	options.push_back( "TX/RX" );
+	return(options);
+}
+
+
+void SoapyHackRF::setAntenna( const int direction, const size_t channel, const std::string &name )
+{
+	/* TODO delete this function or throw if name != RX... */
+}
+
+
+std::string SoapyHackRF::getAntenna( const int direction, const size_t channel ) const
+{
+	return("TX/RX");
+}
+
+
+/*******************************************************************
+ * Frontend corrections API
+ ******************************************************************/
+
+
+bool SoapyHackRF::hasDCOffsetMode( const int direction, const size_t channel ) const
+{
+	return(false);
+}
+
+
+/*******************************************************************
+ * Gain API
+ ******************************************************************/
+
+std::vector<std::string> SoapyHackRF::listGains( const int direction, const size_t channel ) const
+{
+	std::vector<std::string> options;
+	if ( direction == SOAPY_SDR_RX )
+	{
+		options.push_back( "LNA" );
+	}
+	options.push_back( "VGA" );
+	options.push_back( "AMP" );
+
+	return(options);
+	/*
+	 * list available gain elements,
+	 * the functions below have a "name" parameter
+	 */
+}
+
+
+void SoapyHackRF::setGainMode( const int direction, const size_t channel, const bool automatic )
+{
+	/* enable AGC if the hardware supports it, or remove this function */
+}
+
+
+bool SoapyHackRF::getGainMode( const int direction, const size_t channel ) const
+{
+	return(false);
+	/* ditto for the AGC */
+}
+
+
+void SoapyHackRF::setGain( const int direction, const size_t channel, const double value )
+{
+	int32_t ret, gain;
+	gain = value;
+
+	if ( direction == SOAPY_SDR_RX )
+	{
+		if ( gain <= 0 )
+		{
+			_rx_stream->lna_gain	= 0;
+			_rx_stream->vga_gain	= 0;
+			_current_amp		= 0;
+		}else if ( gain <= (HACKRF_RX_LNA_MAX_DB / 2) + (HACKRF_RX_VGA_MAX_DB / 2) )
+		{
+			_rx_stream->vga_gain	= (gain / 3) & ~0x1;
+			_rx_stream->lna_gain	= gain - _rx_stream->vga_gain;
+			_current_amp		= 0;
+		}else if ( gain <= ( (HACKRF_RX_LNA_MAX_DB / 2) + (HACKRF_RX_VGA_MAX_DB / 2) + HACKRF_AMP_MAX_DB) )
+		{
+			_current_amp		= HACKRF_AMP_MAX_DB;
+			_rx_stream->vga_gain	= ( (gain - _current_amp) / 3) & ~0x1;
+			_rx_stream->lna_gain	= gain -_current_amp - _rx_stream->vga_gain;
+		}else if ( gain <= HACKRF_RX_LNA_MAX_DB + HACKRF_RX_VGA_MAX_DB + HACKRF_AMP_MAX_DB )
+		{
+			_current_amp		= HACKRF_AMP_MAX_DB;
+			_rx_stream->vga_gain	= (gain - _current_amp) * double(HACKRF_RX_LNA_MAX_DB) / double(HACKRF_RX_VGA_MAX_DB);
+			_rx_stream->lna_gain	= gain - _current_amp - _rx_stream->vga_gain;
+		}
+
+		_rx_stream->amp_gain=_current_amp;
+
+		ret	= hackrf_set_lna_gain( _dev, _rx_stream->lna_gain );
+		ret	|= hackrf_set_vga_gain( _dev, _rx_stream->vga_gain );
+		ret	|= hackrf_set_amp_enable( _dev, (_current_amp > 0) ? 1 : 0 );
+	}else if ( direction == SOAPY_SDR_TX )
+	{
+		if ( gain <= 0 )
+		{
+			_current_amp		= 0;
+			_tx_stream->vga_gain	= 0;
+		}else if ( gain <= (HACKRF_TX_VGA_MAX_DB / 2) )
+		{
+			_current_amp		= 0;
+			_tx_stream->vga_gain	= gain;
+		}else if ( gain <= HACKRF_TX_VGA_MAX_DB + HACKRF_AMP_MAX_DB )
+		{
+			_current_amp		= HACKRF_AMP_MAX_DB;
+			_tx_stream->vga_gain	= gain - HACKRF_AMP_MAX_DB;
+		}
+
+		_tx_stream->amp_gain=_current_amp;
+
+		ret	= hackrf_set_txvga_gain( _dev, _tx_stream->vga_gain );
+		ret	|= hackrf_set_amp_enable( _dev, (_current_amp > 0) ? 1 : 0 );
+	}
+	if ( ret != HACKRF_SUCCESS )
+	{
+		SoapySDR::logf( SOAPY_SDR_ERROR, "setGain(%f) returned %s", value, hackrf_error_name( (hackrf_error) ret ) );
+	}
+}
+
+
+void SoapyHackRF::setGain( const int direction, const size_t channel, const std::string &name, const double value )
+{
+	if ( name == "AMP" )
+	{
+		_current_amp = value;
+		_current_amp = (_current_amp > 0)?HACKRF_AMP_MAX_DB : 0; //clip to possible values
+
+		if(direction == SOAPY_SDR_RX){
+			_rx_stream->amp_gain=_current_amp;
+		}else if (direction ==SOAPY_SDR_TX){
+			_tx_stream->amp_gain=_current_amp;
+		}
+
+		if ( _dev != NULL )
+		{
+			int ret = hackrf_set_amp_enable( _dev, (_current_amp > 0)?1 : 0 );
+			if ( ret != HACKRF_SUCCESS )
+			{
+				SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_amp_enable(%f) returned %s", _current_amp, hackrf_error_name( (hackrf_error) ret ) );
+			}
+		}
+	}else if ( direction == SOAPY_SDR_RX and name == "LNA" )
+	{
+		_rx_stream->lna_gain = value;
+		if ( _dev != NULL )
+		{
+			int ret = hackrf_set_lna_gain( _dev, _rx_stream->lna_gain );
+			if ( ret != HACKRF_SUCCESS )
+			{
+				SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_lna_gain(%f) returned %s", _rx_stream->lna_gain, hackrf_error_name( (hackrf_error) ret ) );
+			}
+		}
+	}else if ( direction == SOAPY_SDR_RX and name == "VGA" )
+	{
+		_rx_stream->vga_gain = value;
+		if ( _dev != NULL )
+		{
+			int ret = hackrf_set_vga_gain( _dev, _rx_stream->vga_gain );
+			if ( ret != HACKRF_SUCCESS )
+			{
+				SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_vga_gain(%f) returned %s", _rx_stream->vga_gain, hackrf_error_name( (hackrf_error) ret ) );
+			}
+		}
+	}else if ( direction == SOAPY_SDR_TX and name == "VGA" )
+	{
+		_tx_stream->vga_gain = value;
+		if ( _dev != NULL )
+		{
+			int ret = hackrf_set_txvga_gain( _dev, _tx_stream->vga_gain );
+			if ( ret != HACKRF_SUCCESS )
+			{
+				SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_txvga_gain(%f) returned %s", _tx_stream->vga_gain, hackrf_error_name( (hackrf_error) ret ) );
+			}
+		}
+	}
+
+
+	/* set individual gain element by name */
+}
+
+
+double SoapyHackRF::getGain( const int direction, const size_t channel, const std::string &name ) const
+{
+	double gain = 0.0;
+	if ( direction == SOAPY_SDR_RX and name == "AMP" )
+	{
+		gain = -_rx_stream->amp_gain;
+	}else if ( direction == SOAPY_SDR_TX and name == "AMP" )
+	{
+		gain = _tx_stream->amp_gain;
+	}else if ( direction == SOAPY_SDR_RX and name == "LNA" )
+	{
+		gain = _rx_stream->lna_gain;
+	}else if ( direction == SOAPY_SDR_RX and name == "VGA" )
+	{
+		gain = _rx_stream->vga_gain;
+	}else if ( direction == SOAPY_SDR_TX and name == "VGA" )
+	{
+		gain = _tx_stream->vga_gain;
+	}
+
+	return(gain);
+}
+
+
+SoapySDR::Range SoapyHackRF::getGainRange( const int direction, const size_t channel, const std::string &name ) const
+{
+	if ( name == "AMP" )
+		return(SoapySDR::Range( 0, HACKRF_AMP_MAX_DB ) );
+	if ( direction == SOAPY_SDR_RX and name == "LNA" )
+		return(SoapySDR::Range( 0, HACKRF_RX_LNA_MAX_DB ) );
+	if ( direction == SOAPY_SDR_RX and name == "VGA" )
+		return(SoapySDR::Range( 0, HACKRF_RX_VGA_MAX_DB ) );
+	if ( direction == SOAPY_SDR_TX and name == "VGA" )
+		return(SoapySDR::Range( 0, HACKRF_TX_VGA_MAX_DB ) );
+	return(SoapySDR::Range( 0, 0 ) );
+}
+
+
+/*******************************************************************
+ * Frequency API
+ ******************************************************************/
+
+void SoapyHackRF::setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args )
+{
+	if ( name == "BB" )
+		return;
+	if ( name != "RF" )
+		throw std::runtime_error( "setFrequency(" + name + ") unknown name" );
+
+	_current_frequency = frequency;
+
+
+	if(direction==SOAPY_SDR_RX){
+
+		_rx_stream->frequecy=_current_frequency;
+	}
+	if(direction==SOAPY_SDR_TX){
+
+		_tx_stream->frequecy=_current_frequency;
+	}
+
+	if ( _dev != NULL )
+	{
+		int ret = hackrf_set_freq( _dev, _current_frequency );
+
+		if ( ret != HACKRF_SUCCESS )
+		{
+			SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_freq(%f) returned %s", _current_frequency, hackrf_error_name( (hackrf_error) ret ) );
+		}
+	}
+}
+
+
+double SoapyHackRF::getFrequency( const int direction, const size_t channel, const std::string &name ) const
+{
+	if ( name == "BB" )
+		return(0.0);
+	if ( name != "RF" )
+		throw std::runtime_error( "getFrequency(" + name + ") unknown name" );
+
+	double freq;
+
+	if(direction==SOAPY_SDR_RX){
+
+		freq = _rx_stream->frequecy;
+	}
+	if(direction==SOAPY_SDR_TX){
+
+		freq = _tx_stream->frequecy;
+	}
+	return(freq);
+}
+
+SoapySDR::ArgInfoList SoapyHackRF::getFrequencyArgsInfo(const int direction, const size_t channel) const
+{
+	SoapySDR::ArgInfoList freqArgs;
+	// TODO: frequency arguments
+	return freqArgs;
+}
+
+std::vector<std::string> SoapyHackRF::listFrequencies( const int direction, const size_t channel ) const
+{
+	std::vector<std::string> names;
+	names.push_back( "RF" );
+	return(names);
+}
+
+
+SoapySDR::RangeList SoapyHackRF::getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const
+{
+	if ( name == "BB" )
+		return(SoapySDR::RangeList( 1, SoapySDR::Range( 0.0, 0.0 ) ) );
+	if ( name != "RF" )
+		throw std::runtime_error( "getFrequencyRange(" + name + ") unknown name" );
+	return(SoapySDR::RangeList( 1, SoapySDR::Range( 0, 7250000000ull ) ) );
+}
+
+
+/*******************************************************************
+ * Sample Rate API
+ ******************************************************************/
+
+void SoapyHackRF::setSampleRate( const int direction, const size_t channel, const double rate )
+{
+	_current_samplerate = rate;
+
+	if(direction==SOAPY_SDR_RX){
+
+		_rx_stream->samplerate=_current_samplerate;
+	}
+	if(direction==SOAPY_SDR_TX){
+
+		_tx_stream->samplerate=_current_samplerate;
+	}
+
+	if ( _dev != NULL )
+	{
+		int ret = hackrf_set_sample_rate( _dev, _current_samplerate );
+
+		if(_auto_bandwidth){
+
+			_current_bandwidth=hackrf_compute_baseband_filter_bw_round_down_lt(_current_samplerate);
+
+
+			if(direction==SOAPY_SDR_RX){
+
+				_rx_stream->bandwidth=_current_bandwidth;
+			}
+			if(direction==SOAPY_SDR_TX){
+
+				_tx_stream->bandwidth=_current_bandwidth;
+			}
+
+			ret|=hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth);
+		}
+
+		if ( ret != HACKRF_SUCCESS )
+		{
+			SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_sample_rate(%f) returned %s", _current_samplerate, hackrf_error_name( (hackrf_error) ret ) );
+			throw std::runtime_error( "setSampleRate()" );
+		}
+	}
+}
+
+
+double SoapyHackRF::getSampleRate( const int direction, const size_t channel ) const
+{
+	double samp;
+	if(direction==SOAPY_SDR_RX){
+
+		samp= _rx_stream->samplerate;
+	}
+	if(direction==SOAPY_SDR_TX){
+
+		samp= _tx_stream->samplerate;
+	}
+
+	return(samp);
+}
+
+
+std::vector<double> SoapyHackRF::listSampleRates( const int direction, const size_t channel ) const
+{
+	std::vector<double> options;
+	for ( double r = 1e6; r <= 20e6; r += 1e6 )
+	{
+		options.push_back( r );
+	}
+	return(options);
+}
+
+
+void SoapyHackRF::setBandwidth( const int direction, const size_t channel, const double bw )
+{
+	_current_bandwidth = hackrf_compute_baseband_filter_bw(bw);
+
+	if(direction==SOAPY_SDR_RX){
+
+		_rx_stream->bandwidth=_current_bandwidth;
+	}
+	if(direction==SOAPY_SDR_TX){
+
+		_tx_stream->bandwidth=_current_bandwidth;
+	}
+
+	if(_current_bandwidth > 0){
+		_auto_bandwidth=false;
+
+		if ( _dev != NULL )
+		{
+			int ret = hackrf_set_baseband_filter_bandwidth( _dev, _current_bandwidth );
+			if ( ret != HACKRF_SUCCESS )
+			{
+				SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_baseband_filter_bandwidth(%f) returned %s", _current_bandwidth, hackrf_error_name( (hackrf_error) ret ) );
+				throw std::runtime_error( "setBandwidth()" );
+			}
+		}
+
+	}else{
+		_auto_bandwidth=true;
+	}
+
+}
+
+
+double SoapyHackRF::getBandwidth( const int direction, const size_t channel ) const
+{
+	double bw;
+	if(direction==SOAPY_SDR_RX){
+
+		bw = _rx_stream->bandwidth;
+	}
+	if(direction==SOAPY_SDR_TX){
+
+		bw = _tx_stream->bandwidth;
+	}
+
+	return (bw);
+}
+
+
+std::vector<double> SoapyHackRF::listBandwidths( const int direction, const size_t channel ) const
+{
+	std::vector<double> options;
+	options.push_back( 1750000 );
+	options.push_back( 2500000 );
+	options.push_back( 3500000 );
+	options.push_back( 5000000 );
+	options.push_back( 5500000 );
+	options.push_back( 6000000 );
+	options.push_back( 7000000 );
+	options.push_back( 8000000 );
+	options.push_back( 9000000 );
+	options.push_back( 10000000 );
+	options.push_back( 12000000 );
+	options.push_back( 14000000 );
+	options.push_back( 15000000 );
+	options.push_back( 20000000 );
+	options.push_back( 24000000 );
+	options.push_back( 28000000 );
+	return(options);
+}
+
+
diff --git a/HackRF_Streaming.cpp b/HackRF_Streaming.cpp
new file mode 100644
index 0000000..5b3e3de
--- /dev/null
+++ b/HackRF_Streaming.cpp
@@ -0,0 +1,834 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2016 Wei Jiang
+ * 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 "SoapyHackRF.hpp"
+#include <SoapySDR/Logger.hpp>
+#include <chrono>
+#include <thread>
+#include <algorithm> //min
+
+int _hackrf_rx_callback( hackrf_transfer *transfer )
+{
+	SoapyHackRF* obj = (SoapyHackRF *) transfer->rx_ctx;
+	return(obj->hackrf_rx_callback( (int8_t *) transfer->buffer, transfer->valid_length ) );
+}
+
+
+int _hackrf_tx_callback( hackrf_transfer *transfer )
+{
+	SoapyHackRF* obj = (SoapyHackRF *) transfer->tx_ctx;
+	return(obj->hackrf_tx_callback( (int8_t *) transfer->buffer, transfer->valid_length ) );
+}
+
+int SoapyHackRF::hackrf_rx_callback( int8_t *buffer, int32_t length )
+{
+	std::unique_lock<std::mutex> lock(_buf_mutex);
+	_rx_stream->buf_tail = (_rx_stream->buf_head + _rx_stream->buf_count) % _rx_stream->buf_num;
+	memcpy(_rx_stream->buf[_rx_stream->buf_tail], buffer, length );
+
+	if ( _rx_stream->buf_count == _rx_stream->buf_num )
+	{
+		_rx_stream->overflow=true;
+		_rx_stream->buf_head = (_rx_stream->buf_head + 1) % _rx_stream->buf_num;
+	}else  {
+		_rx_stream->buf_count++;
+	}
+	_buf_cond.notify_one();
+
+	return(0);
+}
+
+
+int SoapyHackRF::hackrf_tx_callback( int8_t *buffer, int32_t length  )
+{
+	std::unique_lock<std::mutex> lock(_buf_mutex);
+	if ( _tx_stream->buf_count == 0 )
+	{
+		memset( buffer, 0, length );
+		_tx_stream->underflow=true;
+	}else {
+		memcpy( buffer, _tx_stream->buf[_tx_stream->buf_tail], length );
+		_tx_stream->buf_tail = (_tx_stream->buf_tail + 1) % _tx_stream->buf_num;
+
+		_tx_stream->buf_count--;
+
+		if(_tx_stream->burst_end)
+		{
+			_tx_stream->burst_samps -= (length/BYTES_PER_SAMPLE);
+			if(_tx_stream->burst_samps < 0 ) {
+				_tx_stream->burst_end = false;
+				_tx_stream->burst_samps = 0;
+				return -1;
+			}
+		}
+	}
+	_buf_cond.notify_one();
+
+	return(0);
+}
+
+std::vector<std::string> SoapyHackRF::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");
+	formats.push_back("CF64");
+
+	return formats;
+}
+
+std::string SoapyHackRF::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
+{
+	fullScale = 128;
+	return "CS8";
+}
+
+SoapySDR::ArgInfoList SoapyHackRF::getStreamArgsInfo(const int direction, const size_t channel) const
+{
+	SoapySDR::ArgInfoList streamArgs;
+
+	SoapySDR::ArgInfo buffersArg;
+	buffersArg.key="buffers";
+	buffersArg.value = std::to_string(BUF_NUM);
+	buffersArg.name = "Buffer Count";
+	buffersArg.description = "Number of buffers per read.";
+	buffersArg.units = "buffers";
+	buffersArg.type = SoapySDR::ArgInfo::INT;
+	streamArgs.push_back(buffersArg);
+
+	return streamArgs;
+}
+
+SoapySDR::Stream *SoapyHackRF::setupStream(
+	const int direction,
+	const std::string &format,
+	const std::vector<size_t> &channels,
+	const SoapySDR::Kwargs &args )
+{
+	if ( channels.size() > 1 or( channels.size() > 0 and channels.at( 0 ) != 0 ) )
+	{
+		throw std::runtime_error( "setupStream invalid channel selection" );
+	}
+
+	SoapyHackRFStream * data=new SoapyHackRFStream();
+
+	if(direction==SOAPY_SDR_RX){
+
+		if ( format == "CS8" )
+		{
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." );
+			_rx_stream->format = HACKRF_FORMAT_INT8;
+		}else if ( format == "CS16" )
+		{
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." );
+			_rx_stream->format = HACKRF_FORMAT_INT16;
+		}else if ( format == "CF32" )
+		{
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." );
+			_rx_stream->format= HACKRF_FORMAT_FLOAT32;
+		}else if(format=="CF64"){
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." );
+			_rx_stream->format= HACKRF_FORMAT_FLOAT64;
+		}else throw std::runtime_error( "setupStream invalid format " + format );
+
+		if ( args.count( "buffers" ) != 0 )
+		{
+			try
+			{
+				int numBuffers_in = std::stoi(args.at("buffers"));
+				if (numBuffers_in > 0) {
+					if ( _rx_stream->buf ) {
+						for ( unsigned int i = 0; i < _rx_stream->buf_num; ++i ) {
+							if ( _rx_stream->buf[i] ) {
+								free( _rx_stream->buf[i] );
+							}
+						}
+						free( _rx_stream->buf );
+						_rx_stream->buf = NULL;
+					}
+
+					_rx_stream->buf_num = numBuffers_in;
+				}
+			}
+			catch (const std::invalid_argument &){}
+
+		}
+		_rx_stream->buf = (int8_t * *) malloc( _rx_stream->buf_num * sizeof(int8_t *) );
+		if ( _rx_stream->buf )
+		{
+			for ( unsigned int i = 0; i < _rx_stream->buf_num; ++i )
+				_rx_stream->buf[i] = (int8_t *) malloc( _rx_stream->buf_len );
+		}
+	}
+
+	if(direction==SOAPY_SDR_TX){
+
+		if ( format == "CS8" )
+		{
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." );
+			_tx_stream->format = HACKRF_FORMAT_INT8;
+		}else if ( format == "CS16" )
+		{
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." );
+			_tx_stream->format = HACKRF_FORMAT_INT16;
+		}else if ( format == "CF32" )
+		{
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." );
+			_tx_stream->format= HACKRF_FORMAT_FLOAT32;
+		}else if(format=="CF64"){
+			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." );
+			_tx_stream->format= HACKRF_FORMAT_FLOAT64;
+		}else throw std::runtime_error( "setupStream invalid format " + format );
+
+		if ( args.count( "buffers" ) != 0 )
+		{
+			try
+			{
+				int numBuffers_in = std::stoi(args.at("buffers"));
+				if (numBuffers_in > 0)
+				{
+					if ( _tx_stream->buf )
+					{
+						for ( unsigned int i = 0; i < _tx_stream->buf_num; ++i )
+						{
+							if ( _tx_stream->buf[i] )
+							{
+								free( _tx_stream->buf[i] );
+							}
+						}
+						free( _tx_stream->buf );
+						_tx_stream->buf = NULL;
+					}
+
+					_tx_stream->buf_num = numBuffers_in;
+				}
+			}
+			catch (const std::invalid_argument &){}
+
+		}
+
+		_tx_stream->buf = (int8_t * *) malloc( _tx_stream->buf_num * sizeof(int8_t *) );
+		if ( _tx_stream->buf )
+		{
+			for ( unsigned int i = 0; i < _tx_stream->buf_num; ++i )
+				_tx_stream->buf[i] = (int8_t *) malloc( _tx_stream->buf_len );
+		}
+
+	}
+
+	data->direction=direction;
+
+
+	return ((SoapySDR::Stream *) data );
+}
+
+
+void SoapyHackRF::closeStream( SoapySDR::Stream *stream )
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	delete data;;
+}
+
+
+size_t SoapyHackRF::getStreamMTU( SoapySDR::Stream *stream ) const
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+	size_t mtu;
+	if(data->direction==SOAPY_SDR_RX){
+		mtu =_rx_stream->buf_len/BYTES_PER_SAMPLE;
+
+	}
+	if(data->direction==SOAPY_SDR_TX){
+
+		mtu=_tx_stream->buf_len/BYTES_PER_SAMPLE;
+	}
+	return mtu;
+}
+
+int SoapyHackRF::activateStream(
+	SoapySDR::Stream *stream,
+	const int flags,
+	const long long timeNs,
+	const size_t numElems )
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(data->direction==SOAPY_SDR_RX){
+
+		std::lock_guard<std::mutex> lock(_activate_mutex);
+
+
+		if(_current_mode==TRANSCEIVER_MODE_RX)
+			return 0;
+
+		if(_current_mode==TRANSCEIVER_MODE_TX){
+
+			if(_tx_stream->burst_end){
+
+				while(hackrf_is_streaming(_dev)==HACKRF_TRUE)
+					std::this_thread::sleep_for(std::chrono::milliseconds(10));
+			}
+
+			hackrf_stop_tx(_dev);
+		}
+
+		SoapySDR_logf(SOAPY_SDR_DEBUG, "Start RX");
+
+		//reset buffer tracking before streaming
+		{
+			_rx_stream->buf_count = 0;
+			_rx_stream->buf_head = 0;
+			_rx_stream->buf_tail = 0;
+		}
+
+		int ret = hackrf_start_rx(_dev, _hackrf_rx_callback, (void *) this);
+		if (ret != HACKRF_SUCCESS) {
+			SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_start_rx() failed -- %s", hackrf_error_name(hackrf_error(ret)));
+		}
+
+		ret=hackrf_is_streaming(_dev);
+
+		if (ret==HACKRF_ERROR_STREAMING_EXIT_CALLED){
+
+			hackrf_close(_dev);
+
+			if (_id<0){
+				hackrf_open(&_dev);
+			}else {
+				hackrf_device_list_open(_list,_id,&_dev);
+			}
+			_current_frequency=_rx_stream->frequecy;
+			hackrf_set_freq(_dev,_current_frequency);
+			_current_samplerate=_rx_stream->samplerate;
+			hackrf_set_sample_rate(_dev,_current_samplerate);
+			_current_bandwidth=_rx_stream->bandwidth;
+			hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth);
+			_current_amp=_rx_stream->amp_gain;
+			hackrf_set_amp_enable(_dev,_current_amp);
+			hackrf_set_lna_gain(_dev,_rx_stream->lna_gain);
+			hackrf_set_vga_gain(_dev,_rx_stream->vga_gain);
+			hackrf_start_rx(_dev,_hackrf_rx_callback,(void *) this);
+			ret=hackrf_is_streaming(_dev);
+		}
+		if(ret!=HACKRF_TRUE){
+			SoapySDR_logf(SOAPY_SDR_ERROR,"Activate RX Stream Failed.");
+			return SOAPY_SDR_STREAM_ERROR;
+
+		}
+			_current_mode = TRANSCEIVER_MODE_RX;
+
+	}
+
+	if(data->direction==SOAPY_SDR_TX ){
+
+		std::lock_guard<std::mutex> lock(_activate_mutex);
+
+		if((flags & SOAPY_SDR_END_BURST)!=0 and numElems!=0) {
+			if(_current_mode==TRANSCEIVER_MODE_RX){
+				_tx_stream->buf_head=0;
+				_tx_stream->buf_tail=0;
+				_tx_stream->burst_end = true;
+				_tx_stream->burst_samps = numElems;
+			}
+		}
+
+		if(_current_mode==TRANSCEIVER_MODE_TX)
+			return 0;
+
+		if(_current_mode==TRANSCEIVER_MODE_RX){
+
+			hackrf_stop_rx(_dev);
+		}
+
+		SoapySDR_logf( SOAPY_SDR_DEBUG, "Start TX" );
+
+		int ret = hackrf_start_tx( _dev, _hackrf_tx_callback, (void *) this );
+		if (ret != HACKRF_SUCCESS)
+		{
+			SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_start_tx() failed -- %s", hackrf_error_name(hackrf_error(ret)));
+		}
+
+		ret=hackrf_is_streaming(_dev);
+
+		if (ret==HACKRF_ERROR_STREAMING_EXIT_CALLED){
+
+
+			hackrf_close(_dev);
+
+			if (_id<0){
+				hackrf_open(&_dev);
+			}else {
+				hackrf_device_list_open(_list,_id,&_dev);
+			}
+			_current_frequency=_tx_stream->frequecy;
+			hackrf_set_freq(_dev,_current_frequency);
+			_current_samplerate=_tx_stream->samplerate;
+			hackrf_set_sample_rate(_dev,_current_samplerate);
+			_current_bandwidth=_tx_stream->bandwidth;
+			hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth);
+			_current_amp=_rx_stream->amp_gain;
+			hackrf_set_amp_enable(_dev,_current_amp);
+			hackrf_set_txvga_gain(_dev,_tx_stream->vga_gain);
+			hackrf_set_antenna_enable(_dev,_tx_stream->bias);
+			hackrf_start_tx(_dev,_hackrf_tx_callback,(void *) this);
+			ret=hackrf_is_streaming(_dev);
+		}
+		if(ret!=HACKRF_TRUE){
+
+			SoapySDR_logf(SOAPY_SDR_ERROR,"Activate TX Stream Failed.");
+			return SOAPY_SDR_STREAM_ERROR;
+		}
+			_current_mode = TRANSCEIVER_MODE_TX;
+
+	}
+
+	return(0);
+}
+
+
+int SoapyHackRF::deactivateStream(
+	SoapySDR::Stream *stream,
+	const int flags,
+	const long long timeNs )
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(data->direction==SOAPY_SDR_RX){
+
+		std::lock_guard<std::mutex> lock(_activate_mutex);
+
+		if(_current_mode==TRANSCEIVER_MODE_RX) {
+
+			int ret = hackrf_stop_rx(_dev);
+			if (ret != HACKRF_SUCCESS) {
+				SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_stop_rx() failed -- %s", hackrf_error_name(hackrf_error(ret)));
+			}
+			_current_mode = TRANSCEIVER_MODE_OFF;
+		}
+	}
+
+	if(data->direction==SOAPY_SDR_TX){
+
+		std::lock_guard<std::mutex> lock(_activate_mutex);
+
+		if(_current_mode==TRANSCEIVER_MODE_TX) {
+			int ret = hackrf_stop_tx(_dev);
+			if (ret != HACKRF_SUCCESS) {
+				SoapySDR::logf(SOAPY_SDR_ERROR, "hackrf_stop_tx() failed -- %s", hackrf_error_name(hackrf_error(ret)));
+			}
+			_current_mode = TRANSCEIVER_MODE_OFF;
+		}
+
+	}
+	return(0);
+}
+
+void readbuf(int8_t * src, void * dst, uint32_t len,uint32_t format,size_t offset){
+
+	if(format==HACKRF_FORMAT_INT8){
+		int8_t *samples_cs8=(int8_t *) dst+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			samples_cs8[i*BYTES_PER_SAMPLE] = src[i*BYTES_PER_SAMPLE];
+			samples_cs8[i*BYTES_PER_SAMPLE+1] = src[i*BYTES_PER_SAMPLE+1];
+		}
+
+	}else if(format==HACKRF_FORMAT_INT16){
+
+		int16_t *samples_cs16=(int16_t *) dst+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			samples_cs16[i*BYTES_PER_SAMPLE] = (int16_t)(src[i*BYTES_PER_SAMPLE]<<8);
+			samples_cs16[i*BYTES_PER_SAMPLE+1] = (int16_t)(src[i*BYTES_PER_SAMPLE+1]<<8);
+		}
+	}else if(format==HACKRF_FORMAT_FLOAT32){
+		float *samples_cf32=(float *) dst+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			samples_cf32[i*BYTES_PER_SAMPLE] = (float)(src[i*BYTES_PER_SAMPLE]/127.0);
+			samples_cf32[i*BYTES_PER_SAMPLE+1] = (float)(src[i*BYTES_PER_SAMPLE+1]/127.0);
+		}
+	}else if(format==HACKRF_FORMAT_FLOAT64){
+		double *samples_cf64=(double *) dst+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			samples_cf64[i*BYTES_PER_SAMPLE] = (double)(src[i*BYTES_PER_SAMPLE]/127.0);
+			samples_cf64[i*BYTES_PER_SAMPLE+1] = (double)(src[i*BYTES_PER_SAMPLE+1]/127.0);
+		}
+	} else {
+		SoapySDR_log( SOAPY_SDR_ERROR, "read format not support" );
+	}
+}
+
+
+void writebuf(const void * src, int8_t* dst, uint32_t len,uint32_t format,size_t offset) {
+	if(format==HACKRF_FORMAT_INT8){
+		int8_t *samples_cs8=(int8_t *) src+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			dst[i*BYTES_PER_SAMPLE] = samples_cs8[i*BYTES_PER_SAMPLE];
+			dst[i*BYTES_PER_SAMPLE+1] = samples_cs8[i*BYTES_PER_SAMPLE+1];
+		}
+
+	}else if(format==HACKRF_FORMAT_INT16){
+		int16_t *samples_cs16=(int16_t *) src+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			dst[i*BYTES_PER_SAMPLE] = (int8_t) (samples_cs16[i*BYTES_PER_SAMPLE] >> 8);
+			dst[i*BYTES_PER_SAMPLE+1] = (int8_t) (samples_cs16[i*BYTES_PER_SAMPLE+1] >> 8);
+		}
+	}else if(format==HACKRF_FORMAT_FLOAT32){
+		float *samples_cf32=(float *) src+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			dst[i*BYTES_PER_SAMPLE] = (int8_t) (samples_cf32[i*BYTES_PER_SAMPLE] * 127.0);
+			dst[i*BYTES_PER_SAMPLE+1] = (int8_t) (samples_cf32[i*BYTES_PER_SAMPLE+1] * 127.0);
+		}
+	}else if(format==HACKRF_FORMAT_FLOAT64){
+		double *samples_cf64=(double *) src+offset*BYTES_PER_SAMPLE;
+		for (uint32_t i=0;i<len;++i){
+			dst[i*BYTES_PER_SAMPLE] = (int8_t) (samples_cf64[i*BYTES_PER_SAMPLE] * 127.0);
+			dst[i*BYTES_PER_SAMPLE+1] = (int8_t) (samples_cf64[i*BYTES_PER_SAMPLE+1] * 127.0);
+		}
+
+	}else {
+		SoapySDR_log( SOAPY_SDR_ERROR, "write format not support" );
+
+	}
+}
+
+
+int SoapyHackRF::readStream(
+	SoapySDR::Stream *stream,
+	void * const *buffs,
+	const size_t numElems,
+	int &flags,
+	long long &timeNs,
+	const long timeoutUs )
+{
+	/* this is the user's buffer for channel 0 */
+
+	size_t returnedElems = std::min(numElems,this->getStreamMTU(stream));
+
+	size_t samp_avail=0;
+
+	if(_rx_stream->remainderHandle >= 0){
+
+		const size_t n =std::min(_rx_stream->remainderSamps,returnedElems);
+
+		if(n<returnedElems){
+			samp_avail=n;
+		}
+
+		readbuf(_rx_stream->remainderBuff+_rx_stream->remainderOffset*BYTES_PER_SAMPLE,buffs[0],n,_rx_stream->format,0);
+
+		_rx_stream->remainderOffset+=n;
+		_rx_stream->remainderSamps -=n;
+
+		if(_rx_stream->remainderSamps==0){
+
+			this->releaseReadBuffer(stream,_rx_stream->remainderHandle);
+			_rx_stream->remainderHandle=-1;
+			_rx_stream->remainderOffset=0;
+		}
+
+		if(n==returnedElems)
+			return returnedElems;
+	}
+
+	size_t handle;
+	int ret = this->acquireReadBuffer(stream, handle, (const void **)&_rx_stream->remainderBuff, flags, timeNs, timeoutUs);
+
+	if (ret < 0)
+		return ret;
+
+	_rx_stream->remainderHandle=handle;
+	_rx_stream->remainderSamps=ret;
+
+
+	const size_t n =std::min((returnedElems-samp_avail),_rx_stream->remainderSamps);
+
+	readbuf(_rx_stream->remainderBuff,buffs[0],n,_rx_stream->format,samp_avail);
+	_rx_stream->remainderSamps -=n;
+	_rx_stream->remainderOffset +=n;
+
+	if(_rx_stream->remainderSamps==0){
+		this->releaseReadBuffer(stream,_rx_stream->remainderHandle);
+		_rx_stream->remainderHandle=-1;
+		_rx_stream->remainderOffset=0;
+	}
+
+	return(returnedElems);
+}
+
+
+int SoapyHackRF::writeStream(
+		SoapySDR::Stream *stream,
+		const void * const *buffs,
+		const size_t numElems,
+		int &flags,
+		const long long timeNs,
+		const long timeoutUs )
+{
+
+	size_t returnedElems = std::min(numElems,this->getStreamMTU(stream));
+
+	size_t samp_avail = 0;
+
+	if(_tx_stream->remainderHandle>=0){
+
+		const size_t n =std::min(_tx_stream->remainderSamps,returnedElems);
+
+		if(n<returnedElems){
+			samp_avail=n;
+		}
+
+		writebuf(buffs[0],_tx_stream->remainderBuff+_tx_stream->remainderOffset*BYTES_PER_SAMPLE,n,_tx_stream->format,0);
+		_tx_stream->remainderSamps -=n;
+		_tx_stream->remainderOffset +=n;
+
+		if(_tx_stream->remainderSamps==0){
+			this->releaseWriteBuffer(stream,_tx_stream->remainderHandle,_tx_stream->remainderOffset,flags,timeNs);
+			_tx_stream->remainderHandle=-1;
+			_tx_stream->remainderOffset=0;
+		}
+
+		if(n==returnedElems)
+			return returnedElems;
+
+	}
+
+	size_t handle;
+
+	int ret=this->acquireWriteBuffer(stream,handle,(void **)&_tx_stream->remainderBuff,timeoutUs);
+	if (ret<0)return ret;
+
+	_tx_stream->remainderHandle=handle;
+	_tx_stream->remainderSamps=ret;
+
+	const size_t n =std::min((returnedElems-samp_avail),_tx_stream->remainderSamps);
+
+	writebuf(buffs[0],_tx_stream->remainderBuff,n,_tx_stream->format,samp_avail);
+	_tx_stream->remainderSamps -=n;
+	_tx_stream->remainderOffset +=n;
+
+	if(_tx_stream->remainderSamps==0){
+		this->releaseWriteBuffer(stream,_tx_stream->remainderHandle,_tx_stream->remainderOffset,flags,timeNs);
+		_tx_stream->remainderHandle=-1;
+		_tx_stream->remainderOffset=0;
+	}
+
+	return returnedElems;
+
+}
+
+
+int SoapyHackRF::readStreamStatus(
+		SoapySDR::Stream *stream,
+		size_t &chanMask,
+		int &flags,
+		long long &timeNs,
+		const long timeoutUs
+){
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(data->direction!=SOAPY_SDR_TX){
+
+		return SOAPY_SDR_NOT_SUPPORTED;
+	}
+
+	//calculate when the loop should exit
+	const auto timeout = std::chrono::duration_cast<std::chrono::high_resolution_clock::duration>(std::chrono::microseconds(timeoutUs));
+	const auto exitTime = std::chrono::high_resolution_clock::now() + timeout;
+
+	//poll for status events until the timeout expires
+	while (true)
+	{
+		if(_tx_stream->underflow){
+			_tx_stream->underflow=false;
+			SoapySDR::log(SOAPY_SDR_SSI, "U");
+			return SOAPY_SDR_UNDERFLOW;
+		}
+
+		//sleep for a fraction of the total timeout
+		const auto sleepTimeUs = std::min<long>(1000, timeoutUs/10);
+		std::this_thread::sleep_for(std::chrono::microseconds(sleepTimeUs));
+
+		//check for timeout expired
+		const auto timeNow = std::chrono::high_resolution_clock::now();
+		if (exitTime < timeNow) return SOAPY_SDR_TIMEOUT;
+	}
+}
+
+int SoapyHackRF::acquireReadBuffer(
+		SoapySDR::Stream *stream,
+		size_t &handle,
+		const void **buffs,
+		int &flags,
+		long long &timeNs,
+		const long timeoutUs)
+{
+
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(data->direction!=SOAPY_SDR_RX){
+		return SOAPY_SDR_NOT_SUPPORTED;
+	}
+
+	if ( _current_mode!=TRANSCEIVER_MODE_RX ) {
+
+		//wait for tx to be consumed before switching
+		const auto exitTime = std::chrono::high_resolution_clock::now() + std::chrono::microseconds(timeoutUs);
+		while (true)
+		{
+			std::unique_lock <std::mutex> lock( _buf_mutex );
+			if (_tx_stream->buf_count == 0) break;
+			if (std::chrono::high_resolution_clock::now() > exitTime) return SOAPY_SDR_TIMEOUT;
+		}
+
+		int ret=this->activateStream(stream);
+		if(ret<0) return ret;
+	}
+
+	std::unique_lock <std::mutex> lock( _buf_mutex );
+
+	while (_rx_stream->buf_count == 0)
+	{
+		_buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs));
+		if (_rx_stream->buf_count == 0) return SOAPY_SDR_TIMEOUT;
+	}
+
+	if(_rx_stream->overflow) {
+		flags|=SOAPY_SDR_END_ABRUPT;
+		_rx_stream->overflow=false;
+		SoapySDR::log(SOAPY_SDR_SSI,"O");
+		return  SOAPY_SDR_OVERFLOW;
+	}
+
+	handle=_rx_stream->buf_head;
+	_rx_stream->buf_head = (_rx_stream->buf_head + 1) % _rx_stream->buf_num;
+	this->getDirectAccessBufferAddrs(stream,handle,(void **)buffs);
+
+	return this->getStreamMTU(stream);
+}
+
+void SoapyHackRF::releaseReadBuffer(
+		SoapySDR::Stream *stream,
+		const size_t handle)
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(!_tx_stream->burst_end){
+
+		std::unique_lock <std::mutex> lock( _buf_mutex );
+
+		_rx_stream->buf_count--;
+	}
+
+}
+
+int SoapyHackRF::acquireWriteBuffer(
+		SoapySDR::Stream *stream,
+		size_t &handle,
+		void **buffs,
+		const long timeoutUs)
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(data->direction!=SOAPY_SDR_TX){
+
+		return SOAPY_SDR_NOT_SUPPORTED;
+	}
+
+	if(_current_mode!=TRANSCEIVER_MODE_TX) {
+		int ret=this->activateStream(stream);
+		if(ret<0) return ret;
+	}
+
+	std::unique_lock <std::mutex> lock( _buf_mutex );
+
+	while ( _tx_stream->buf_count == _tx_stream->buf_num )
+	{
+		_buf_cond.wait_for(lock, std::chrono::microseconds(timeoutUs));
+		if (_tx_stream->buf_count == _tx_stream->buf_num) return SOAPY_SDR_TIMEOUT;
+	}
+
+	handle=_tx_stream->buf_head;
+	_tx_stream->buf_head = (_tx_stream->buf_head + 1) % _tx_stream->buf_num;
+
+	this->getDirectAccessBufferAddrs(stream,handle,buffs);
+
+	if(_tx_stream->burst_end){
+		if((_tx_stream->burst_samps - int32_t(this->getStreamMTU(stream))) < 0){
+			memset(buffs[0],0,this->getStreamMTU(stream));
+			return _tx_stream->burst_samps;
+		}
+	}
+	return this->getStreamMTU(stream);
+
+}
+
+void SoapyHackRF::releaseWriteBuffer(
+		SoapySDR::Stream *stream,
+		const size_t handle,
+		const size_t numElems,
+		int &flags,
+		const long long timeNs)
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	std::unique_lock <std::mutex> lock( _buf_mutex );
+
+	_tx_stream->buf_count++;
+}
+
+size_t SoapyHackRF::getNumDirectAccessBuffers(
+		SoapySDR::Stream *stream)
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	size_t buffers;
+	if(data->direction==SOAPY_SDR_RX){
+		buffers =_rx_stream->buf_num;
+
+	}
+	if(data->direction==SOAPY_SDR_TX){
+
+		buffers=_tx_stream->buf_num;
+	}
+
+	return buffers;
+}
+
+int SoapyHackRF::getDirectAccessBufferAddrs(
+		SoapySDR::Stream *stream,
+		const size_t handle,
+		void **buffs)
+{
+	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+
+	if(data->direction==SOAPY_SDR_RX){
+		buffs[0]=(void *)_rx_stream->buf[handle];
+
+	}
+	if(data->direction==SOAPY_SDR_TX){
+
+		buffs[0]=(void *)_tx_stream->buf[handle];
+	}
+
+	return 0;
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..20efd1b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 
+
+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/README.md b/README.md
new file mode 100644
index 0000000..84e0e23
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# Soapy SDR module for Hack RF
+
+##Build Status
+
+- Travis: [![Travis Build Status](https://travis-ci.org/pothosware/SoapyHackRF.svg?branch=master)](https://travis-ci.org/pothosware/SoapyHackRF)
+
+##Dependencies
+
+* SoapySDR - https://github.com/pothosware/SoapySDR/wiki
+* libhackrf - https://github.com/mossmann/hackrf/wiki
+
+##Documentation
+
+* https://github.com/pothosware/SoapyHackRF/wiki
+
+## Licensing information
+
+The MIT License (MIT)
+
+Copyright (c) 2015
+
+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/SoapyHackRF.hpp b/SoapyHackRF.hpp
new file mode 100644
index 0000000..885c6f0
--- /dev/null
+++ b/SoapyHackRF.hpp
@@ -0,0 +1,374 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015
+ * 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 <hackrf.h>
+#include <string.h>
+#include <mutex>
+#include <condition_variable>
+#include <SoapySDR/Device.hpp>
+#include <SoapySDR/Logger.hpp>
+
+#define BUF_LEN			262144
+#define BUF_NUM			15
+#define BYTES_PER_SAMPLE	2
+#define HACKRF_RX_VGA_MAX_DB 62
+#define HACKRF_TX_VGA_MAX_DB 47
+#define HACKRF_RX_LNA_MAX_DB 40
+#define HACKRF_AMP_MAX_DB 14
+
+enum HackRF_Format {
+	HACKRF_FORMAT_FLOAT32	=0,
+	HACKRF_FORMAT_INT16	=1,
+	HACKRF_FORMAT_INT8	=2,
+	HACKRF_FORMAT_FLOAT64 =3,
+};
+
+
+/*!
+ * The session object manages hackrf_init/exit
+ * with a process-wide reference count.
+ */
+class SoapyHackRFSession
+{
+public:
+	SoapyHackRFSession(void);
+	~SoapyHackRFSession(void);
+};
+
+class SoapyHackRF : public SoapySDR::Device
+{
+public:
+	SoapyHackRF( const SoapySDR::Kwargs & args );
+
+	~SoapyHackRF( void );
+
+
+	/*******************************************************************
+	 * Identification API
+	 ******************************************************************/
+
+	std::string getDriverKey( void ) const;
+
+
+	std::string getHardwareKey( void ) const;
+
+
+	SoapySDR::Kwargs getHardwareInfo( void ) const;
+
+
+	/*******************************************************************
+	 * Channels API
+	 ******************************************************************/
+
+	size_t getNumChannels( const int ) const;
+
+
+	bool getFullDuplex( const int direction, const size_t channel ) const;
+
+
+	/*******************************************************************
+	 * Stream API
+	 ******************************************************************/
+
+	std::vector<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 );
+
+
+	int writeStream(
+			SoapySDR::Stream *stream,
+			const void * const *buffs,
+			const size_t numElems,
+			int &flags,
+			const long long timeNs = 0,
+			const long timeoutUs = 100000);
+
+	int readStreamStatus(
+			SoapySDR::Stream *stream,
+			size_t &chanMask,
+			int &flags,
+			long long &timeNs,
+			const long timeoutUs
+	);
+
+
+	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);
+
+	int acquireWriteBuffer(
+			SoapySDR::Stream *stream,
+			size_t &handle,
+			void **buffs,
+			const long timeoutUs = 100000);
+
+	void releaseWriteBuffer(
+			SoapySDR::Stream *stream,
+			const size_t handle,
+			const size_t numElems,
+			int &flags,
+			const long long timeNs = 0);
+
+	size_t getNumDirectAccessBuffers(SoapySDR::Stream *stream);
+
+	int getDirectAccessBufferAddrs(SoapySDR::Stream *stream, const size_t handle, void **buffs);
+
+	/*******************************************************************
+	 * 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;
+
+
+	/*******************************************************************
+	 * 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;
+
+
+	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;
+
+
+	SoapySDR::ArgInfoList getFrequencyArgsInfo(const int direction, const size_t channel) 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;
+
+
+	/*******************************************************************
+	 * 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;
+
+	/*******************************************************************
+ 	 * HackRF callback
+ 	 ******************************************************************/
+	int hackrf_tx_callback( int8_t *buffer, int32_t length );
+
+
+	int hackrf_rx_callback( int8_t *buffer, int32_t length );
+
+
+
+
+private:
+
+	struct RXStream{
+		uint32_t vga_gain;
+		uint32_t lna_gain;
+		uint8_t amp_gain;
+		double samplerate;
+		uint32_t bandwidth;
+		uint64_t frequecy;
+
+		int32_t remainderHandle;
+		size_t remainderSamps;
+		size_t remainderOffset;
+		int8_t* remainderBuff;
+		uint32_t format;
+
+		uint32_t	buf_num;
+		uint32_t	buf_len;
+		int8_t		**buf;
+		uint32_t	buf_head;
+		uint32_t	buf_tail;
+		uint32_t	buf_count;
+
+		bool overflow;
+	} ;
+
+
+	struct TXStream{
+		uint32_t vga_gain;
+		uint8_t amp_gain;
+		double samplerate;
+		uint32_t bandwidth;
+		uint64_t frequecy;
+		bool bias;
+
+		int32_t remainderHandle;
+		size_t remainderSamps;
+		size_t remainderOffset;
+		int8_t* remainderBuff;
+		uint32_t format;
+
+		uint32_t	buf_num;
+		uint32_t	buf_len;
+		int8_t		**buf;
+		uint32_t	buf_head;
+		uint32_t	buf_tail;
+		uint32_t	buf_count;
+		bool underflow;
+
+		bool burst_end;
+		int32_t burst_samps;
+	} ;
+
+	struct SoapyHackRFStream
+	{
+		RXStream * rxStream;
+		TXStream * txStream;
+		int32_t  direction;
+	};
+
+
+	RXStream * _rx_stream;
+	TXStream * _tx_stream;
+
+	bool _auto_bandwidth;
+
+	hackrf_device * _dev;
+
+	hackrf_device_list_t * _list;
+
+	uint64_t _current_frequency;
+
+	double _current_samplerate;
+
+	uint32_t _current_bandwidth;
+
+	uint8_t _current_amp;
+
+	int32_t _id;
+	std::mutex	_activate_mutex;
+	std::mutex	_buf_mutex;
+	std::condition_variable _buf_cond;
+
+	transceiver_mode_t _current_mode;
+
+	SoapyHackRFSession _sess;
+};
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..ab4be00
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,17 @@
+soapyhackrf (0.2.1) unstable; urgency=low
+
+  * Release 0.2.1 (2016-02-29)
+
+ -- Josh Blum <josh at pothosware.com>  Mon, 29 Feb 2016 13:19:38 -0800
+
+soapyhackrf (0.2.0) unstable; urgency=low
+
+  * Release 0.2.0 (2015-11-20)
+
+ -- Josh Blum <josh at pothosware.com>  Fri, 23 Oct 2015 18:39:30 -0700
+
+soapyhackrf (0.1.0) unstable; urgency=low
+
+  * Release 0.1.0 (2015-10-10)
+
+ -- Josh Blum <josh at pothosware.com>  Sat, 10 Oct 2015 11:34:51 -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..e006d7b
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,30 @@
+Source: soapyhackrf
+Section: libs
+Priority: optional
+Maintainer: jocover <jiangwei0402 at gmail.com>
+Uploaders: Josh Blum <josh at pothosware.com>
+Build-Depends:
+    debhelper (>= 9.0.0),
+    cmake,
+    libhackrf-dev,
+    libsoapysdr-dev
+Standards-Version: 3.9.8
+Homepage: https://github.com/pothosware/SoapyHackRF/wiki
+Vcs-Git: https://github.com/pothosware/SoapyHackRF.git
+Vcs-Browser: https://github.com/pothosware/SoapyHackRF
+
+Package: soapysdr0.5-2-module-hackrf
+Architecture: any
+Multi-Arch: same
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Soapy HackRF - HackRF device support for Soapy SDR.
+ A Soapy module that supports HackRF devices within the Soapy API.
+
+Package: soapysdr-module-hackrf
+Architecture: all
+Depends: soapysdr0.5-2-module-hackrf, ${misc:Depends}
+Description: Soapy HackRF - HackRF device support for Soapy SDR.
+ A Soapy module that supports HackRF devices within the Soapy API.
+ .
+ This is an empty dependency package that pulls in the HackRF module
+ for the default version of libsoapysdr.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..1d5caa2
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,26 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: soapyhackrf
+Source: https://github.com/pothosware/SoapyHackRF/wiki
+
+Files: *
+Copyright:
+    Copyright (c) 2015-2016 Wei Jiang
+    Copyright (c) 2015 Josh Blum
+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..6eb429c
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+export DEB_HOST_MULTIARCH
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+	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-hackrf.install b/debian/soapysdr0.5-2-module-hackrf.install
new file mode 100644
index 0000000..f1d0181
--- /dev/null
+++ b/debian/soapysdr0.5-2-module-hackrf.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)
diff --git a/self_test.py b/self_test.py
new file mode 100644
index 0000000..11ebc95
--- /dev/null
+++ b/self_test.py
@@ -0,0 +1,81 @@
+import SoapySDR
+from SoapySDR import * #SOAPY_SDR_* constants
+import numpy as np
+import time
+
+if __name__ == "__main__":
+    hackrf = SoapySDR.Device(dict(driver="hackrf"))
+    print hackrf
+
+    hackrf.setSampleRate(SOAPY_SDR_RX, 0, 8e6)
+    hackrf.setSampleRate(SOAPY_SDR_TX, 0, 8e6)
+
+    """
+    for i in range(5):
+        print("  Make rx stream #%d"%i)
+        rxStream = hackrf.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0])
+        for j in range(5):
+            numSampsTotal = 10000
+            print("    Activate, get %d samples, Deactivate #%d"%(numSampsTotal, j))
+            hackrf.activateStream(rxStream)
+            buff = np.array([0]*1024, np.complex64)
+            while numSampsTotal > 0:
+                sr = hackrf.readStream(rxStream, [buff], buff.size, timeoutUs=int(1e6))
+                #print sr
+                assert(sr.ret > 0)
+                numSampsTotal -= sr.ret
+            hackrf.deactivateStream(rxStream)
+        hackrf.closeStream(rxStream)
+
+    for i in range(5):
+        print("  Make tx stream #%d"%i)
+        txStream = hackrf.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0])
+        for j in range(5):
+            numSampsTotal = 10000
+            print("    Activate, send %d samples, Deactivate #%d"%(numSampsTotal, j))
+            hackrf.activateStream(txStream)
+            buff = np.array([0]*1024, np.complex64)
+            while numSampsTotal != 0:
+                size = min(buff.size, numSampsTotal)
+                sr = hackrf.writeStream(txStream, [buff], size)
+                #print sr
+                if not (sr.ret > 0): print("Fail %s, %d"%(sr, numSampsTotal))
+                assert(sr.ret > 0)
+                numSampsTotal -= sr.ret
+            hackrf.deactivateStream(txStream)
+        hackrf.closeStream(txStream)
+    """
+
+    ####################################################################
+    #setup both streams at once
+    ####################################################################
+    rxStream = hackrf.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32, [0])
+    txStream = hackrf.setupStream(SOAPY_SDR_TX, SOAPY_SDR_CF32, [0])
+
+    hackrf.activateStream(txStream)
+    hackrf.activateStream(txStream)
+
+    numSampsTotal = 10000
+    hackrf.activateStream(rxStream)
+    buff = np.array([0]*1024, np.complex64)
+    while numSampsTotal > 0:
+        sr = hackrf.readStream(rxStream, [buff], buff.size, timeoutUs=int(1e6))
+        #print sr
+        assert(sr.ret > 0)
+        numSampsTotal -= sr.ret
+
+    numSampsTotal = 10000
+    buff = np.array([0]*1024, np.complex64)
+    while numSampsTotal != 0:
+        size = min(buff.size, numSampsTotal)
+        sr = hackrf.writeStream(txStream, [buff], size)
+        #print sr
+        if not (sr.ret > 0): print("Fail %s, %d"%(sr, numSampsTotal))
+        assert(sr.ret > 0)
+        numSampsTotal -= sr.ret
+
+    hackrf.deactivateStream(txStream)
+    hackrf.deactivateStream(txStream)
+
+    hackrf.closeStream(rxStream)
+    hackrf.closeStream(txStream)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/soapyhackrf.git



More information about the pkg-hamradio-commits mailing list