[hamradio-commits] [soapyhackrf] 01/08: New upstream version 0.3.1

Andreas E. Bombe aeb at moszumanska.debian.org
Sun Aug 6 22:54:25 UTC 2017


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

aeb pushed a commit to branch master
in repository soapyhackrf.

commit 8b225d312a96f2ead8df146139512a18eb2f2872
Author: Andreas Bombe <aeb at debian.org>
Date:   Sun Aug 6 17:00:03 2017 -0400

    New upstream version 0.3.1
---
 Changelog.txt                                      |  13 +
 HackRF_Registation.cpp                             |  27 +-
 HackRF_Settings.cpp                                | 273 +++++-------
 HackRF_Streaming.cpp                               | 461 ++++++++++-----------
 README.md                                          |   6 +-
 SoapyHackRF.hpp                                    |  86 ++--
 debian/changelog                                   |  12 +
 debian/control                                     |   4 +-
 debian/copyright                                   |   3 +-
 debian/rules                                       |   0
 ...f.install => soapysdr0.6-module-hackrf.install} |   0
 self_test.py                                       |   4 +-
 12 files changed, 428 insertions(+), 461 deletions(-)

diff --git a/Changelog.txt b/Changelog.txt
index 67d8516..31b4fc8 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,16 @@
+Release 0.3.1 (2017-06-19)
+==========================
+
+- Cache discovered HackRF results for claimed devices
+
+Release 0.3.0 (2017-04-29)
+==========================
+
+- Major cleanup for thread safety and buffer management
+- Added label convention to hackrf discovery routine
+- Support filtering specific devices by serial number
+- Switch to format constants in streaming implementation
+
 Release 0.2.2 (2016-10-19)
 ==========================
 
diff --git a/HackRF_Registation.cpp b/HackRF_Registation.cpp
index e69f02b..baee6bb 100644
--- a/HackRF_Registation.cpp
+++ b/HackRF_Registation.cpp
@@ -2,6 +2,7 @@
  * The MIT License (MIT)
  *
  * Copyright (c) 2015 Wei Jiang
+ * Copyright (c) 2015-2017 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
@@ -22,7 +23,7 @@
 #include "SoapyHackRF.hpp"
 #include <SoapySDR/Registry.hpp>
 
-
+static std::map<std::string, SoapySDR::Kwargs> _cachedResults;
 
 static std::vector<SoapySDR::Kwargs> find_HackRF(const SoapySDR::Kwargs &args)
 {
@@ -72,7 +73,21 @@ static std::vector<SoapySDR::Kwargs> find_HackRF(const SoapySDR::Kwargs &args)
 						read_partid_serialno.serial_no[3]);
 				options["serial"] = serial_str;
 
-				results.push_back(options);
+				//generate a displayable label string with trimmed serial
+				size_t ofs = 0;
+				while (ofs < sizeof(serial_str) and serial_str[ofs] == '0') ofs++;
+				char label_str[100];
+				sprintf(label_str, "%s #%d %s", options["device"].c_str(), i, serial_str+ofs);
+				options["label"] = label_str;
+
+				//filter based on serial and idx
+				const bool serialMatch = args.count("serial") == 0 or args.at("serial") == options["serial"];
+				const bool idxMatch = args.count("hackrf") == 0 or std::stoi(args.at("hackrf")) == i;
+				if (serialMatch and idxMatch)
+				{
+					results.push_back(options);
+					_cachedResults[serial_str] = options;
+				}
 
 				hackrf_close(device);
 			}
@@ -83,6 +98,14 @@ static std::vector<SoapySDR::Kwargs> find_HackRF(const SoapySDR::Kwargs &args)
 
 	hackrf_device_list_free(list);
 
+	//fill in the cached results for claimed handles
+	for (const auto &serial : HackRF_getClaimedSerials())
+	{
+		if (_cachedResults.count(serial) == 0) continue;
+		if (args.count("serial") != 0 and args.at("serial") != serial) continue;
+		results.push_back(_cachedResults.at(serial));
+	}
+
 	return results;
 }
 
diff --git a/HackRF_Settings.cpp b/HackRF_Settings.cpp
index ab62a05..4a8f1a6 100644
--- a/HackRF_Settings.cpp
+++ b/HackRF_Settings.cpp
@@ -2,6 +2,8 @@
  * The MIT License (MIT)
  *
  * Copyright (c) 2015-2016 Wei Jiang
+ * Copyright (c) 2015-2017 Josh Blum
+ * Copyright (c) 2017 Kevin Mehall
  * 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
@@ -21,55 +23,33 @@
 
 #include "SoapyHackRF.hpp"
 
+std::set<std::string> &HackRF_getClaimedSerials(void)
+{
+	static std::set<std::string> serials;
+	return serials;
+}
 
 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;
+	if (args.count("label") != 0)
+		SoapySDR_logf( SOAPY_SDR_INFO, "Opening %s...", args.at("label").c_str());
+
+	_rx_stream.vga_gain=16;
+	_rx_stream.lna_gain=16;
+	_rx_stream.amp_gain=0;
+	_rx_stream.frequency=0;
+	_rx_stream.samplerate=0;
+	_rx_stream.bandwidth=0;
+	_rx_stream.overflow = false;
+
+	_tx_stream.vga_gain=0;
+	_tx_stream.amp_gain=0;
+	_tx_stream.frequency=0;
+	_tx_stream.samplerate=0;
+	_tx_stream.bandwidth=0;
+	_tx_stream.burst_samps=0;
+	_tx_stream.burst_end=false;
+	_tx_stream.underflow = false;
 
 	_current_mode=HACKRF_TRANSCEIVER_MODE_OFF;
 
@@ -77,7 +57,9 @@ SoapyHackRF::SoapyHackRF( const SoapySDR::Kwargs &args )
 
 	_dev		= nullptr;
 
-	_list= nullptr;
+	if (args.count("serial") == 0)
+		throw std::runtime_error("no hackrf device matches");
+	_serial = args.at("serial");
 
 	_current_amp = 0;
 
@@ -87,89 +69,26 @@ SoapyHackRF::SoapyHackRF( const SoapySDR::Kwargs &args )
 
 	_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_by_serial(_serial.c_str(), &_dev);
+	if ( ret != HACKRF_SUCCESS )
 	{
-		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");
-		}
+		SoapySDR_logf( SOAPY_SDR_INFO, "Could not Open HackRF Device" );
+		throw std::runtime_error("hackrf open failed");
 	}
 
-
-
+	HackRF_getClaimedSerials().insert(_serial);
 }
 
 
 SoapyHackRF::~SoapyHackRF( void )
 {
+	HackRF_getClaimedSerials().erase(_serial);
+
 	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 */
 }
 
@@ -187,6 +106,7 @@ std::string SoapyHackRF::getDriverKey( void ) const
 
 std::string SoapyHackRF::getHardwareKey( void ) const
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	uint8_t board_id=BOARD_ID_INVALID;
 
 	hackrf_board_id_read(_dev,&board_id);
@@ -197,6 +117,7 @@ std::string SoapyHackRF::getHardwareKey( void ) const
 
 SoapySDR::Kwargs SoapyHackRF::getHardwareInfo( void ) const
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	SoapySDR::Kwargs info;
 
 	char version_str[100];
@@ -267,8 +188,9 @@ SoapySDR::ArgInfoList SoapyHackRF::getSettingInfo(void) const
 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);
+		std::lock_guard<std::mutex> lock(_device_mutex);
+		_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");
@@ -281,7 +203,7 @@ void SoapyHackRF::writeSetting(const std::string &key, const std::string &value)
 std::string SoapyHackRF::readSetting(const std::string &key) const
 {
 	if (key == "bias_tx") {
-		return _tx_stream->bias?"true":"false";
+		return _tx_stream.bias?"true":"false";
 	}
 	return "";
 }
@@ -357,57 +279,58 @@ bool SoapyHackRF::getGainMode( const int direction, const size_t channel ) const
 
 void SoapyHackRF::setGain( const int direction, const size_t channel, const double value )
 {
-	int32_t ret, gain;
+	std::lock_guard<std::mutex> lock(_device_mutex);
+	int32_t ret(0), gain(0);
 	gain = value;
 
 	if ( direction == SOAPY_SDR_RX )
 	{
 		if ( gain <= 0 )
 		{
-			_rx_stream->lna_gain	= 0;
-			_rx_stream->vga_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;
+			_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;
+			_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.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;
+		_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_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;
+			_tx_stream.vga_gain	= 0;
 		}else if ( gain <= (HACKRF_TX_VGA_MAX_DB / 2) )
 		{
 			_current_amp		= 0;
-			_tx_stream->vga_gain	= gain;
+			_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.vga_gain	= gain - HACKRF_AMP_MAX_DB;
 		}
 
-		_tx_stream->amp_gain=_current_amp;
+		_tx_stream.amp_gain=_current_amp;
 
-		ret	= hackrf_set_txvga_gain( _dev, _tx_stream->vga_gain );
+		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 )
@@ -419,15 +342,16 @@ void SoapyHackRF::setGain( const int direction, const size_t channel, const doub
 
 void SoapyHackRF::setGain( const int direction, const size_t channel, const std::string &name, const double value )
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	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;
+			_rx_stream.amp_gain=_current_amp;
 		}else if (direction ==SOAPY_SDR_TX){
-			_tx_stream->amp_gain=_current_amp;
+			_tx_stream.amp_gain=_current_amp;
 		}
 
 		if ( _dev != NULL )
@@ -440,35 +364,35 @@ void SoapyHackRF::setGain( const int direction, const size_t channel, const std:
 		}
 	}else if ( direction == SOAPY_SDR_RX and name == "LNA" )
 	{
-		_rx_stream->lna_gain = value;
+		_rx_stream.lna_gain = value;
 		if ( _dev != NULL )
 		{
-			int ret = hackrf_set_lna_gain( _dev, _rx_stream->lna_gain );
+			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 ) );
+				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;
+		_rx_stream.vga_gain = value;
 		if ( _dev != NULL )
 		{
-			int ret = hackrf_set_vga_gain( _dev, _rx_stream->vga_gain );
+			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 ) );
+				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;
+		_tx_stream.vga_gain = value;
 		if ( _dev != NULL )
 		{
-			int ret = hackrf_set_txvga_gain( _dev, _tx_stream->vga_gain );
+			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 ) );
+				SoapySDR::logf( SOAPY_SDR_ERROR, "hackrf_set_txvga_gain(%f) returned %s", _tx_stream.vga_gain, hackrf_error_name( (hackrf_error) ret ) );
 			}
 		}
 	}
@@ -480,22 +404,23 @@ void SoapyHackRF::setGain( const int direction, const size_t channel, const std:
 
 double SoapyHackRF::getGain( const int direction, const size_t channel, const std::string &name ) const
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	double gain = 0.0;
 	if ( direction == SOAPY_SDR_RX and name == "AMP" )
 	{
-		gain = -_rx_stream->amp_gain;
+		gain = -_rx_stream.amp_gain;
 	}else if ( direction == SOAPY_SDR_TX and name == "AMP" )
 	{
-		gain = _tx_stream->amp_gain;
+		gain = _tx_stream.amp_gain;
 	}else if ( direction == SOAPY_SDR_RX and name == "LNA" )
 	{
-		gain = _rx_stream->lna_gain;
+		gain = _rx_stream.lna_gain;
 	}else if ( direction == SOAPY_SDR_RX and name == "VGA" )
 	{
-		gain = _rx_stream->vga_gain;
+		gain = _rx_stream.vga_gain;
 	}else if ( direction == SOAPY_SDR_TX and name == "VGA" )
 	{
-		gain = _tx_stream->vga_gain;
+		gain = _tx_stream.vga_gain;
 	}
 
 	return(gain);
@@ -527,16 +452,17 @@ void SoapyHackRF::setFrequency( const int direction, const size_t channel, const
 	if ( name != "RF" )
 		throw std::runtime_error( "setFrequency(" + name + ") unknown name" );
 
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	_current_frequency = frequency;
 
 
 	if(direction==SOAPY_SDR_RX){
 
-		_rx_stream->frequecy=_current_frequency;
+		_rx_stream.frequency=_current_frequency;
 	}
 	if(direction==SOAPY_SDR_TX){
 
-		_tx_stream->frequecy=_current_frequency;
+		_tx_stream.frequency=_current_frequency;
 	}
 
 	if ( _dev != NULL )
@@ -558,15 +484,16 @@ double SoapyHackRF::getFrequency( const int direction, const size_t channel, con
 	if ( name != "RF" )
 		throw std::runtime_error( "getFrequency(" + name + ") unknown name" );
 
-	double freq;
+	std::lock_guard<std::mutex> lock(_device_mutex);
+	double freq(0.0);
 
 	if(direction==SOAPY_SDR_RX){
 
-		freq = _rx_stream->frequecy;
+		freq = _rx_stream.frequency;
 	}
 	if(direction==SOAPY_SDR_TX){
 
-		freq = _tx_stream->frequecy;
+		freq = _tx_stream.frequency;
 	}
 	return(freq);
 }
@@ -602,15 +529,16 @@ SoapySDR::RangeList SoapyHackRF::getFrequencyRange( const int direction, const s
 
 void SoapyHackRF::setSampleRate( const int direction, const size_t channel, const double rate )
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	_current_samplerate = rate;
 
 	if(direction==SOAPY_SDR_RX){
 
-		_rx_stream->samplerate=_current_samplerate;
+		_rx_stream.samplerate=_current_samplerate;
 	}
 	if(direction==SOAPY_SDR_TX){
 
-		_tx_stream->samplerate=_current_samplerate;
+		_tx_stream.samplerate=_current_samplerate;
 	}
 
 	if ( _dev != NULL )
@@ -624,11 +552,11 @@ void SoapyHackRF::setSampleRate( const int direction, const size_t channel, cons
 
 			if(direction==SOAPY_SDR_RX){
 
-				_rx_stream->bandwidth=_current_bandwidth;
+				_rx_stream.bandwidth=_current_bandwidth;
 			}
 			if(direction==SOAPY_SDR_TX){
 
-				_tx_stream->bandwidth=_current_bandwidth;
+				_tx_stream.bandwidth=_current_bandwidth;
 			}
 
 			ret|=hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth);
@@ -645,14 +573,15 @@ void SoapyHackRF::setSampleRate( const int direction, const size_t channel, cons
 
 double SoapyHackRF::getSampleRate( const int direction, const size_t channel ) const
 {
-	double samp;
+	std::lock_guard<std::mutex> lock(_device_mutex);
+	double samp(0.0);
 	if(direction==SOAPY_SDR_RX){
 
-		samp= _rx_stream->samplerate;
+		samp= _rx_stream.samplerate;
 	}
 	if(direction==SOAPY_SDR_TX){
 
-		samp= _tx_stream->samplerate;
+		samp= _tx_stream.samplerate;
 	}
 
 	return(samp);
@@ -672,15 +601,16 @@ std::vector<double> SoapyHackRF::listSampleRates( const int direction, const siz
 
 void SoapyHackRF::setBandwidth( const int direction, const size_t channel, const double bw )
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
 	_current_bandwidth = hackrf_compute_baseband_filter_bw(bw);
 
 	if(direction==SOAPY_SDR_RX){
 
-		_rx_stream->bandwidth=_current_bandwidth;
+		_rx_stream.bandwidth=_current_bandwidth;
 	}
 	if(direction==SOAPY_SDR_TX){
 
-		_tx_stream->bandwidth=_current_bandwidth;
+		_tx_stream.bandwidth=_current_bandwidth;
 	}
 
 	if(_current_bandwidth > 0){
@@ -705,14 +635,15 @@ void SoapyHackRF::setBandwidth( const int direction, const size_t channel, const
 
 double SoapyHackRF::getBandwidth( const int direction, const size_t channel ) const
 {
-	double bw;
+	std::lock_guard<std::mutex> lock(_device_mutex);
+	double bw(0.0);
 	if(direction==SOAPY_SDR_RX){
 
-		bw = _rx_stream->bandwidth;
+		bw = _rx_stream.bandwidth;
 	}
 	if(direction==SOAPY_SDR_TX){
 
-		bw = _tx_stream->bandwidth;
+		bw = _tx_stream.bandwidth;
 	}
 
 	return (bw);
@@ -740,5 +671,3 @@ std::vector<double> SoapyHackRF::listBandwidths( const int direction, const size
 	options.push_back( 28000000 );
 	return(options);
 }
-
-
diff --git a/HackRF_Streaming.cpp b/HackRF_Streaming.cpp
index fd74223..a331e64 100644
--- a/HackRF_Streaming.cpp
+++ b/HackRF_Streaming.cpp
@@ -2,6 +2,8 @@
  * The MIT License (MIT)
  *
  * Copyright (c) 2015-2016 Wei Jiang
+ * Copyright (c) 2015-2017 Josh Blum
+ * Copyright (c) 2017 Kevin Mehall
  * 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
@@ -21,6 +23,7 @@
 
 #include "SoapyHackRF.hpp"
 #include <SoapySDR/Logger.hpp>
+#include <SoapySDR/Formats.hpp>
 #include <chrono>
 #include <thread>
 #include <algorithm> //min
@@ -41,15 +44,15 @@ int _hackrf_tx_callback( hackrf_transfer *transfer )
 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 );
+	_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 )
+	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;
+		_rx_stream.overflow=true;
+		_rx_stream.buf_head = (_rx_stream.buf_head + 1) % _rx_stream.buf_num;
 	}else  {
-		_rx_stream->buf_count++;
+		_rx_stream.buf_count++;
 	}
 	_buf_cond.notify_one();
 
@@ -60,22 +63,22 @@ int SoapyHackRF::hackrf_rx_callback( int8_t *buffer, int32_t length )
 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 )
+	if ( _tx_stream.buf_count == 0 )
 	{
 		memset( buffer, 0, length );
-		_tx_stream->underflow=true;
+		_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;
+		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--;
+		_tx_stream.buf_count--;
 
-		if(_tx_stream->burst_end)
+		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;
+			_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;
 			}
 		}
@@ -89,10 +92,10 @@ std::vector<std::string> SoapyHackRF::getStreamFormats(const int direction, cons
 {
 	std::vector<std::string> formats;
 
-	formats.push_back("CS8");
-	formats.push_back("CS16");
-	formats.push_back("CF32");
-	formats.push_back("CF64");
+	formats.push_back(SOAPY_SDR_CS8);
+	formats.push_back(SOAPY_SDR_CS16);
+	formats.push_back(SOAPY_SDR_CF32);
+	formats.push_back(SOAPY_SDR_CF64);
 
 	return formats;
 }
@@ -100,7 +103,7 @@ std::vector<std::string> SoapyHackRF::getStreamFormats(const int direction, cons
 std::string SoapyHackRF::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
 {
 	fullScale = 128;
-	return "CS8";
+	return SOAPY_SDR_CS8;
 }
 
 SoapySDR::ArgInfoList SoapyHackRF::getStreamArgsInfo(const int direction, const size_t channel) const
@@ -119,87 +122,113 @@ SoapySDR::ArgInfoList SoapyHackRF::getStreamArgsInfo(const int direction, const
 	return streamArgs;
 }
 
+void SoapyHackRF::Stream::allocate_buffers() {
+	buf = (int8_t * *) malloc( buf_num * sizeof(int8_t *) );
+	if ( buf ) {
+		for ( unsigned int i = 0; i < buf_num; ++i ) {
+			buf[i] = (int8_t *) malloc( buf_len );
+		}
+	}
+}
+
+void SoapyHackRF::Stream::clear_buffers() {
+	if ( buf ) {
+		for ( unsigned int i = 0; i < buf_num; ++i ) {
+			if ( buf[i] ) {
+				free( buf[i] );
+			}
+		}
+		free( buf );
+		buf = NULL;
+	}
+
+	buf_count = 0;
+	buf_tail = 0;
+	buf_head = 0;
+	remainderSamps = 0;
+	remainderOffset = 0;
+	remainderBuff = nullptr;
+	remainderHandle = -1;
+}
+
 SoapySDR::Stream *SoapyHackRF::setupStream(
 	const int direction,
 	const std::string &format,
 	const std::vector<size_t> &channels,
 	const SoapySDR::Kwargs &args )
 {
+	std::lock_guard<std::mutex> lock(_device_mutex);
+
 	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 (_rx_stream.opened) {
+			throw std::runtime_error("RX stream already opened");
+		}
 
-		if ( format == "CS8" )
+		if ( format == SOAPY_SDR_CS8 )
 		{
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." );
-			_rx_stream->format = HACKRF_FORMAT_INT8;
-		}else if ( format == "CS16" )
+			_rx_stream.format = HACKRF_FORMAT_INT8;
+		}else if ( format == SOAPY_SDR_CS16 )
 		{
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." );
-			_rx_stream->format = HACKRF_FORMAT_INT16;
-		}else if ( format == "CF32" )
+			_rx_stream.format = HACKRF_FORMAT_INT16;
+		}else if ( format == SOAPY_SDR_CF32 )
 		{
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." );
-			_rx_stream->format= HACKRF_FORMAT_FLOAT32;
-		}else if(format=="CF64"){
+			_rx_stream.format= HACKRF_FORMAT_FLOAT32;
+		}else if(format==SOAPY_SDR_CF64){
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." );
-			_rx_stream->format= HACKRF_FORMAT_FLOAT64;
+			_rx_stream.format= HACKRF_FORMAT_FLOAT64;
 		}else throw std::runtime_error( "setupStream invalid format " + format );
 
+		_rx_stream.buf_num = BUF_NUM;
+
 		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;
+					_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 );
-		}
-	}
+		_rx_stream.allocate_buffers();
 
-	if(direction==SOAPY_SDR_TX){
+		_rx_stream.opened = true;
 
-		if ( format == "CS8" )
+		return RX_STREAM;
+	} else if(direction==SOAPY_SDR_TX){
+		if (_tx_stream.opened) {
+			throw std::runtime_error("TX stream already opened");
+		}
+
+		if ( format == SOAPY_SDR_CS8 )
 		{
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS8." );
-			_tx_stream->format = HACKRF_FORMAT_INT8;
-		}else if ( format == "CS16" )
+			_tx_stream.format = HACKRF_FORMAT_INT8;
+		}else if ( format == SOAPY_SDR_CS16 )
 		{
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CS16." );
-			_tx_stream->format = HACKRF_FORMAT_INT16;
-		}else if ( format == "CF32" )
+			_tx_stream.format = HACKRF_FORMAT_INT16;
+		}else if ( format == SOAPY_SDR_CF32 )
 		{
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF32." );
-			_tx_stream->format= HACKRF_FORMAT_FLOAT32;
-		}else if(format=="CF64"){
+			_tx_stream.format= HACKRF_FORMAT_FLOAT32;
+		}else if(format==SOAPY_SDR_CF64){
 			SoapySDR_log( SOAPY_SDR_DEBUG, "Using format CF64." );
-			_tx_stream->format= HACKRF_FORMAT_FLOAT64;
+			_tx_stream.format= HACKRF_FORMAT_FLOAT64;
 		}else throw std::runtime_error( "setupStream invalid format " + format );
 
+		_tx_stream.buf_num = BUF_NUM;
+
 		if ( args.count( "buffers" ) != 0 )
 		{
 			try
@@ -207,63 +236,44 @@ SoapySDR::Stream *SoapyHackRF::setupStream(
 				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;
+					_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 );
-		}
+		_tx_stream.allocate_buffers();
+		_tx_stream.opened = true;
 
+		return TX_STREAM;
+	} else {
+		throw std::runtime_error("Invalid direction");
 	}
-
-	data->direction=direction;
-
-
-	return ((SoapySDR::Stream *) data );
 }
 
-
 void SoapyHackRF::closeStream( SoapySDR::Stream *stream )
 {
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
-
-	delete data;;
+	std::lock_guard<std::mutex> lock(_device_mutex);
+	if (stream == RX_STREAM) {
+		_rx_stream.clear_buffers();
+		_rx_stream.opened = false;
+	} else if (stream == TX_STREAM) {
+		_tx_stream.clear_buffers();
+		_tx_stream.opened = false;
+	}
 }
 
 
 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;
+	if(stream == RX_STREAM){
+		return _rx_stream.buf_len/BYTES_PER_SAMPLE;
+	} else if(stream == TX_STREAM){
+		return _tx_stream.buf_len/BYTES_PER_SAMPLE;
+	} else {
+		throw std::runtime_error("Invalid stream");
 	}
-	return mtu;
 }
 
 int SoapyHackRF::activateStream(
@@ -272,11 +282,10 @@ int SoapyHackRF::activateStream(
 	const long long timeNs,
 	const size_t numElems )
 {
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
 
-	if(data->direction==SOAPY_SDR_RX){
+	if(stream == RX_STREAM){
 
-		std::lock_guard<std::mutex> lock(_activate_mutex);
+		std::lock_guard<std::mutex> lock(_device_mutex);
 
 
 		if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX)
@@ -284,7 +293,7 @@ int SoapyHackRF::activateStream(
 
 		if(_current_mode==HACKRF_TRANSCEIVER_MODE_TX){
 
-			if(_tx_stream->burst_end){
+			if(_tx_stream.burst_end){
 
 				while(hackrf_is_streaming(_dev)==HACKRF_TRUE)
 					std::this_thread::sleep_for(std::chrono::milliseconds(10));
@@ -297,9 +306,9 @@ int SoapyHackRF::activateStream(
 
 		//reset buffer tracking before streaming
 		{
-			_rx_stream->buf_count = 0;
-			_rx_stream->buf_head = 0;
-			_rx_stream->buf_tail = 0;
+			_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);
@@ -312,22 +321,17 @@ int SoapyHackRF::activateStream(
 		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_open_by_serial(_serial.c_str(), &_dev);
+			_current_frequency=_rx_stream.frequency;
 			hackrf_set_freq(_dev,_current_frequency);
-			_current_samplerate=_rx_stream->samplerate;
+			_current_samplerate=_rx_stream.samplerate;
 			hackrf_set_sample_rate(_dev,_current_samplerate);
-			_current_bandwidth=_rx_stream->bandwidth;
+			_current_bandwidth=_rx_stream.bandwidth;
 			hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth);
-			_current_amp=_rx_stream->amp_gain;
+			_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_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);
 		}
@@ -338,18 +342,16 @@ int SoapyHackRF::activateStream(
 		}
 			_current_mode = HACKRF_TRANSCEIVER_MODE_RX;
 
-	}
-
-	if(data->direction==SOAPY_SDR_TX ){
+	} else if (stream == TX_STREAM) {
 
-		std::lock_guard<std::mutex> lock(_activate_mutex);
+		std::lock_guard<std::mutex> lock(_device_mutex);
 
 		if((flags & SOAPY_SDR_END_BURST)!=0 and numElems!=0) {
 			if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX){
-				_tx_stream->buf_head=0;
-				_tx_stream->buf_tail=0;
-				_tx_stream->burst_end = true;
-				_tx_stream->burst_samps = numElems;
+				_tx_stream.buf_head=0;
+				_tx_stream.buf_tail=0;
+				_tx_stream.burst_end = true;
+				_tx_stream.burst_samps = numElems;
 			}
 		}
 
@@ -375,22 +377,17 @@ int SoapyHackRF::activateStream(
 
 
 			hackrf_close(_dev);
-
-			if (_id<0){
-				hackrf_open(&_dev);
-			}else {
-				hackrf_device_list_open(_list,_id,&_dev);
-			}
-			_current_frequency=_tx_stream->frequecy;
+			hackrf_open_by_serial(_serial.c_str(), &_dev);
+			_current_frequency=_tx_stream.frequency;
 			hackrf_set_freq(_dev,_current_frequency);
-			_current_samplerate=_tx_stream->samplerate;
+			_current_samplerate=_tx_stream.samplerate;
 			hackrf_set_sample_rate(_dev,_current_samplerate);
-			_current_bandwidth=_tx_stream->bandwidth;
+			_current_bandwidth=_tx_stream.bandwidth;
 			hackrf_set_baseband_filter_bandwidth(_dev,_current_bandwidth);
-			_current_amp=_rx_stream->amp_gain;
+			_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_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);
 		}
@@ -412,11 +409,10 @@ int SoapyHackRF::deactivateStream(
 	const int flags,
 	const long long timeNs )
 {
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
 
-	if(data->direction==SOAPY_SDR_RX){
+	if(stream == RX_STREAM){
 
-		std::lock_guard<std::mutex> lock(_activate_mutex);
+		std::lock_guard<std::mutex> lock(_device_mutex);
 
 		if(_current_mode==HACKRF_TRANSCEIVER_MODE_RX) {
 
@@ -426,11 +422,9 @@ int SoapyHackRF::deactivateStream(
 			}
 			_current_mode = HACKRF_TRANSCEIVER_MODE_OFF;
 		}
-	}
-
-	if(data->direction==SOAPY_SDR_TX){
+	} else if(stream == TX_STREAM) {
 
-		std::lock_guard<std::mutex> lock(_activate_mutex);
+		std::lock_guard<std::mutex> lock(_device_mutex);
 
 		if(_current_mode==HACKRF_TRANSCEIVER_MODE_TX) {
 			int ret = hackrf_stop_tx(_dev);
@@ -520,30 +514,32 @@ int SoapyHackRF::readStream(
 	long long &timeNs,
 	const long timeoutUs )
 {
+	if(stream != RX_STREAM){
+		return SOAPY_SDR_NOT_SUPPORTED;
+	}
 	/* 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){
+	if(_rx_stream.remainderHandle >= 0){
 
-		const size_t n =std::min(_rx_stream->remainderSamps,returnedElems);
+		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);
+		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;
+		_rx_stream.remainderOffset+=n;
+		_rx_stream.remainderSamps -=n;
 
-		if(_rx_stream->remainderSamps==0){
+		if(_rx_stream.remainderSamps==0){
 
-			this->releaseReadBuffer(stream,_rx_stream->remainderHandle);
-			_rx_stream->remainderHandle=-1;
-			_rx_stream->remainderOffset=0;
+			this->releaseReadBuffer(stream,_rx_stream.remainderHandle);
+			_rx_stream.remainderHandle=-1;
+			_rx_stream.remainderOffset=0;
 		}
 
 		if(n==returnedElems)
@@ -551,25 +547,25 @@ int SoapyHackRF::readStream(
 	}
 
 	size_t handle;
-	int ret = this->acquireReadBuffer(stream, handle, (const void **)&_rx_stream->remainderBuff, flags, timeNs, timeoutUs);
+	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;
+	_rx_stream.remainderHandle=handle;
+	_rx_stream.remainderSamps=ret;
 
 
-	const size_t n =std::min((returnedElems-samp_avail),_rx_stream->remainderSamps);
+	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;
+	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;
+	if(_rx_stream.remainderSamps==0){
+		this->releaseReadBuffer(stream,_rx_stream.remainderHandle);
+		_rx_stream.remainderHandle=-1;
+		_rx_stream.remainderOffset=0;
 	}
 
 	return(returnedElems);
@@ -584,27 +580,30 @@ int SoapyHackRF::writeStream(
 		const long long timeNs,
 		const long timeoutUs )
 {
+	if(stream != TX_STREAM){
+		return SOAPY_SDR_NOT_SUPPORTED;
+	}
 
 	size_t returnedElems = std::min(numElems,this->getStreamMTU(stream));
 
 	size_t samp_avail = 0;
 
-	if(_tx_stream->remainderHandle>=0){
+	if(_tx_stream.remainderHandle>=0){
 
-		const size_t n =std::min(_tx_stream->remainderSamps,returnedElems);
+		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;
+		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(_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)
@@ -614,22 +613,22 @@ int SoapyHackRF::writeStream(
 
 	size_t handle;
 
-	int ret=this->acquireWriteBuffer(stream,handle,(void **)&_tx_stream->remainderBuff,timeoutUs);
+	int ret=this->acquireWriteBuffer(stream,handle,(void **)&_tx_stream.remainderBuff,timeoutUs);
 	if (ret<0)return ret;
 
-	_tx_stream->remainderHandle=handle;
-	_tx_stream->remainderSamps=ret;
+	_tx_stream.remainderHandle=handle;
+	_tx_stream.remainderSamps=ret;
 
-	const size_t n =std::min((returnedElems-samp_avail),_tx_stream->remainderSamps);
+	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;
+	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;
+	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;
@@ -644,10 +643,8 @@ int SoapyHackRF::readStreamStatus(
 		long long &timeNs,
 		const long timeoutUs
 ){
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
-
-	if(data->direction!=SOAPY_SDR_TX){
 
+	if(stream != TX_STREAM){
 		return SOAPY_SDR_NOT_SUPPORTED;
 	}
 
@@ -658,8 +655,8 @@ int SoapyHackRF::readStreamStatus(
 	//poll for status events until the timeout expires
 	while (true)
 	{
-		if(_tx_stream->underflow){
-			_tx_stream->underflow=false;
+		if(_tx_stream.underflow){
+			_tx_stream.underflow=false;
 			SoapySDR::log(SOAPY_SDR_SSI, "U");
 			return SOAPY_SDR_UNDERFLOW;
 		}
@@ -683,9 +680,8 @@ int SoapyHackRF::acquireReadBuffer(
 		const long timeoutUs)
 {
 
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
 
-	if(data->direction!=SOAPY_SDR_RX){
+	if(stream != RX_STREAM){
 		return SOAPY_SDR_NOT_SUPPORTED;
 	}
 
@@ -696,7 +692,7 @@ int SoapyHackRF::acquireReadBuffer(
 		while (true)
 		{
 			std::unique_lock <std::mutex> lock( _buf_mutex );
-			if (_tx_stream->buf_count == 0) break;
+			if (_tx_stream.buf_count == 0) break;
 			if (std::chrono::high_resolution_clock::now() > exitTime) return SOAPY_SDR_TIMEOUT;
 		}
 
@@ -706,21 +702,21 @@ int SoapyHackRF::acquireReadBuffer(
 
 	std::unique_lock <std::mutex> lock( _buf_mutex );
 
-	while (_rx_stream->buf_count == 0)
+	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.buf_count == 0) return SOAPY_SDR_TIMEOUT;
 	}
 
-	if(_rx_stream->overflow) {
+	if(_rx_stream.overflow) {
 		flags|=SOAPY_SDR_END_ABRUPT;
-		_rx_stream->overflow=false;
+		_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;
+	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);
@@ -730,13 +726,15 @@ void SoapyHackRF::releaseReadBuffer(
 		SoapySDR::Stream *stream,
 		const size_t handle)
 {
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
+	if(stream != RX_STREAM){
+		throw std::runtime_error("Invalid stream");
+	}
 
-	if(!_tx_stream->burst_end){
+	if(!_tx_stream.burst_end){
 
 		std::unique_lock <std::mutex> lock( _buf_mutex );
 
-		_rx_stream->buf_count--;
+		_rx_stream.buf_count--;
 	}
 
 }
@@ -747,10 +745,8 @@ int SoapyHackRF::acquireWriteBuffer(
 		void **buffs,
 		const long timeoutUs)
 {
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
-
-	if(data->direction!=SOAPY_SDR_TX){
 
+	if(stream != TX_STREAM){
 		return SOAPY_SDR_NOT_SUPPORTED;
 	}
 
@@ -761,21 +757,21 @@ int SoapyHackRF::acquireWriteBuffer(
 
 	std::unique_lock <std::mutex> lock( _buf_mutex );
 
-	while ( _tx_stream->buf_count == _tx_stream->buf_num )
+	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;
+		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;
+	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){
+	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 _tx_stream.burst_samps;
 		}
 	}
 	return this->getStreamMTU(stream);
@@ -789,29 +785,24 @@ void SoapyHackRF::releaseWriteBuffer(
 		int &flags,
 		const long long timeNs)
 {
-	SoapyHackRFStream * data = (SoapyHackRFStream*)stream;
-
-	std::unique_lock <std::mutex> lock( _buf_mutex );
-
-	_tx_stream->buf_count++;
+	if (stream == TX_STREAM) {
+		std::unique_lock <std::mutex> lock( _buf_mutex );
+		_tx_stream.buf_count++;
+	} else {
+		throw std::runtime_error("Invalid stream");
+	}
 }
 
 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;
+	if (stream == RX_STREAM) {
+		return _rx_stream.buf_num;
+	} else if(stream == TX_STREAM){
+		return _tx_stream.buf_num;
+	} else {
+		throw std::runtime_error("Invalid stream");
 	}
-
-	return buffers;
 }
 
 int SoapyHackRF::getDirectAccessBufferAddrs(
@@ -819,15 +810,13 @@ int SoapyHackRF::getDirectAccessBufferAddrs(
 		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];
+	if (stream == RX_STREAM) {
+		buffs[0]=(void *)_rx_stream.buf[handle];
+	} else if (stream == TX_STREAM) {
+		buffs[0]=(void *)_tx_stream.buf[handle];
+	} else {
+		throw std::runtime_error("Invalid stream");
 	}
 
 	return 0;
diff --git a/README.md b/README.md
index 84e0e23..49a1147 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
 # Soapy SDR module for Hack RF
 
-##Build Status
+## Build Status
 
 - Travis: [![Travis Build Status](https://travis-ci.org/pothosware/SoapyHackRF.svg?branch=master)](https://travis-ci.org/pothosware/SoapyHackRF)
 
-##Dependencies
+## Dependencies
 
 * SoapySDR - https://github.com/pothosware/SoapySDR/wiki
 * libhackrf - https://github.com/mossmann/hackrf/wiki
 
-##Documentation
+## Documentation
 
 * https://github.com/pothosware/SoapyHackRF/wiki
 
diff --git a/SoapyHackRF.hpp b/SoapyHackRF.hpp
index 53c5547..a6591bd 100644
--- a/SoapyHackRF.hpp
+++ b/SoapyHackRF.hpp
@@ -1,7 +1,9 @@
 /*
  * The MIT License (MIT)
  *
- * Copyright (c) 2015
+ * Copyright (c) 2015 Wei Jiang
+ * Copyright (c) 2015-2017 Josh Blum
+ * Copyright (c) 2017 Kevin Mehall
  * 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
@@ -26,6 +28,7 @@
 #include <condition_variable>
 #include <SoapySDR/Device.hpp>
 #include <SoapySDR/Logger.hpp>
+#include <set>
 
 #define BUF_LEN			262144
 #define BUF_NUM			15
@@ -48,6 +51,7 @@ typedef enum {
 	HACKRF_TRANSCEIVER_MODE_TX = 2,
 } HackRF_transceiver_mode_t;
 
+std::set<std::string> &HackRF_getClaimedSerials(void);
 
 /*!
  * The session object manages hackrf_init/exit
@@ -293,20 +297,16 @@ public:
 
 private:
 
-	struct RXStream{
-		uint32_t vga_gain;
-		uint32_t lna_gain;
-		uint8_t amp_gain;
-		double samplerate;
-		uint32_t bandwidth;
-		uint64_t frequecy;
+	SoapySDR::Stream* const TX_STREAM = (SoapySDR::Stream*) 0x1;
+	SoapySDR::Stream* const RX_STREAM = (SoapySDR::Stream*) 0x2;
 
-		int32_t remainderHandle;
-		size_t remainderSamps;
-		size_t remainderOffset;
-		int8_t* remainderBuff;
-		uint32_t format;
+	struct Stream {
+		Stream(): opened(false), buf_num(BUF_NUM), buf_len(BUF_LEN), buf(nullptr),
+				  buf_head(0), buf_tail(0), buf_count(0),
+				  remainderHandle(-1), remainderSamps(0), remainderOffset(0), remainderBuff(nullptr),
+				  format(HACKRF_FORMAT_INT8) {}
 
+		bool opened;
 		uint32_t	buf_num;
 		uint32_t	buf_len;
 		int8_t		**buf;
@@ -314,52 +314,49 @@ private:
 		uint32_t	buf_tail;
 		uint32_t	buf_count;
 
-		bool overflow;
-	} ;
+		int32_t remainderHandle;
+		size_t remainderSamps;
+		size_t remainderOffset;
+		int8_t* remainderBuff;
+		uint32_t format;
 
+		~Stream() { clear_buffers(); }
+		void clear_buffers();
+		void allocate_buffers();
+	};
 
-	struct TXStream{
+	struct RXStream: Stream {
 		uint32_t vga_gain;
+		uint32_t lna_gain;
 		uint8_t amp_gain;
 		double samplerate;
 		uint32_t bandwidth;
-		uint64_t frequecy;
-		bool bias;
+		uint64_t frequency;
 
-		int32_t remainderHandle;
-		size_t remainderSamps;
-		size_t remainderOffset;
-		int8_t* remainderBuff;
-		uint32_t format;
+		bool overflow;
+	};
+
+	struct TXStream: Stream {
+		uint32_t vga_gain;
+		uint8_t amp_gain;
+		double samplerate;
+		uint32_t bandwidth;
+		uint64_t frequency;
+		bool bias;
 
-		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;
+	RXStream _rx_stream;
+	TXStream _tx_stream;
 
 	bool _auto_bandwidth;
 
 	hackrf_device * _dev;
-
-	hackrf_device_list_t * _list;
+	std::string _serial;
 
 	uint64_t _current_frequency;
 
@@ -369,8 +366,11 @@ private:
 
 	uint8_t _current_amp;
 
-	int32_t _id;
-	std::mutex	_activate_mutex;
+	/// Mutex protecting all use of the hackrf device _dev and other instance variables.
+	/// Most of the hackrf API is thread-safe because it only calls libusb, however
+	/// the activateStream() method in this library can close and re-open the device,
+	/// so all use of _dev must be protected
+	mutable std::mutex	_device_mutex;
 	std::mutex	_buf_mutex;
 	std::condition_variable _buf_cond;
 
diff --git a/debian/changelog b/debian/changelog
index 7ef1c22..4381ccb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+soapyhackrf (0.3.1-1) unstable; urgency=low
+
+  * Release 0.3.1 (2017-06-19)
+
+ -- Josh Blum <josh at pothosware.com>  Mon, 19 Jun 2017 20:18:21 -0000
+
+soapyhackrf (0.3.0-1) unstable; urgency=low
+
+  * Release 0.3.0 (2017-04-29)
+
+ -- Josh Blum <josh at pothosware.com>  Sat, 29 Apr 2017 15:04:55 -0000
+
 soapyhackrf (0.2.2) unstable; urgency=low
 
   * Release 0.2.2 (2016-10-19)
diff --git a/debian/control b/debian/control
index e006d7b..270397a 100644
--- a/debian/control
+++ b/debian/control
@@ -13,7 +13,7 @@ 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
+Package: soapysdr0.6-module-hackrf
 Architecture: any
 Multi-Arch: same
 Depends: ${shlibs:Depends}, ${misc:Depends}
@@ -22,7 +22,7 @@ Description: Soapy HackRF - HackRF device support for Soapy SDR.
 
 Package: soapysdr-module-hackrf
 Architecture: all
-Depends: soapysdr0.5-2-module-hackrf, ${misc:Depends}
+Depends: soapysdr0.6-module-hackrf, ${misc:Depends}
 Description: Soapy HackRF - HackRF device support for Soapy SDR.
  A Soapy module that supports HackRF devices within the Soapy API.
  .
diff --git a/debian/copyright b/debian/copyright
index 1d5caa2..a98a3bf 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -5,7 +5,8 @@ Source: https://github.com/pothosware/SoapyHackRF/wiki
 Files: *
 Copyright:
     Copyright (c) 2015-2016 Wei Jiang
-    Copyright (c) 2015 Josh Blum
+    Copyright (c) 2015-2017 Josh Blum
+    Copyright (c) 2017 Kevin Mehall
 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
diff --git a/debian/rules b/debian/rules
old mode 100644
new mode 100755
diff --git a/debian/soapysdr0.5-2-module-hackrf.install b/debian/soapysdr0.6-module-hackrf.install
similarity index 100%
rename from debian/soapysdr0.5-2-module-hackrf.install
rename to debian/soapysdr0.6-module-hackrf.install
diff --git a/self_test.py b/self_test.py
index 11ebc95..49129f5 100644
--- a/self_test.py
+++ b/self_test.py
@@ -52,7 +52,7 @@ if __name__ == "__main__":
     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(rxStream)
     hackrf.activateStream(txStream)
 
     numSampsTotal = 10000
@@ -74,7 +74,7 @@ if __name__ == "__main__":
         assert(sr.ret > 0)
         numSampsTotal -= sr.ret
 
-    hackrf.deactivateStream(txStream)
+    hackrf.deactivateStream(rxStream)
     hackrf.deactivateStream(txStream)
 
     hackrf.closeStream(rxStream)

-- 
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