diff --git a/.gitignore b/.gitignore
index 588976d8e..f13285b5f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ build/*
 LOCAL/*
 .cproject
 .project
+.settings/
diff --git a/cmake/Modules/FindLibBLADERF.cmake b/cmake/Modules/FindLibBLADERF.cmake
new file mode 100644
index 000000000..8741c9d46
--- /dev/null
+++ b/cmake/Modules/FindLibBLADERF.cmake
@@ -0,0 +1,28 @@
+if(NOT LIBBLADERF_FOUND)
+
+  pkg_check_modules (LIBBLADERF_PKG libbladeRF)
+  find_path(LIBBLADERF_INCLUDE_DIR NAMES libbladeRF.h
+    PATHS
+    ${LIBBLADERF_PKG_INCLUDE_DIRS}
+    /usr/include
+    /usr/local/include
+  )
+
+  find_library(LIBBLADERF_LIBRARIES NAMES bladeRF
+    PATHS
+    ${LIBBLADERF_PKG_LIBRARY_DIRS}
+    /usr/lib
+    /usr/local/lib
+  )
+
+  if(LIBBLADERF_INCLUDE_DIR AND LIBBLADERF_LIBRARIES)
+    set(LIBBLADERF_FOUND TRUE CACHE INTERNAL "libbladerf found")
+    message(STATUS "Found libbladerf: ${LIBBLADERF_INCLUDE_DIR}, ${LIBBLADERF_LIBRARIES}")
+  else(LIBBLADERF_INCLUDE_DIR AND LIBBLADERF_LIBRARIES)
+    set(LIBBLADERF_FOUND FALSE CACHE INTERNAL "libbladerf found")
+    message(STATUS "libbladerf not found.")
+  endif(LIBBLADERF_INCLUDE_DIR AND LIBBLADERF_LIBRARIES)
+
+  mark_as_advanced(LIBBLADERF_INCLUDE_DIR LIBBLADERF_LIBRARIES)
+
+endif(NOT LIBBLADERDF_FOUND)
diff --git a/include/plugin/plugingui.h b/include/plugin/plugingui.h
index 586e44678..d0e2e3543 100644
--- a/include/plugin/plugingui.h
+++ b/include/plugin/plugingui.h
@@ -12,6 +12,7 @@ public:
 	virtual void destroy() = 0;
 
 	virtual void setName(const QString& name) = 0;
+	virtual QString getName() const = 0;
 
 	virtual void resetToDefaults() = 0;
 
diff --git a/plugins/channel/am/amdemodgui.cpp b/plugins/channel/am/amdemodgui.cpp
index 6c4460bda..d6d73442b 100644
--- a/plugins/channel/am/amdemodgui.cpp
+++ b/plugins/channel/am/amdemodgui.cpp
@@ -34,6 +34,11 @@ void AMDemodGUI::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString AMDemodGUI::getName() const
+{
+	return objectName();
+}
+
 void AMDemodGUI::resetToDefaults()
 {
 	ui->rfBW->setValue(4);
diff --git a/plugins/channel/am/amdemodgui.h b/plugins/channel/am/amdemodgui.h
index 0ee51e09b..95d13944f 100644
--- a/plugins/channel/am/amdemodgui.h
+++ b/plugins/channel/am/amdemodgui.h
@@ -25,6 +25,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serialize() const;
diff --git a/plugins/channel/lora/lorademodgui.cpp b/plugins/channel/lora/lorademodgui.cpp
index 8de48e910..2d74f1d97 100644
--- a/plugins/channel/lora/lorademodgui.cpp
+++ b/plugins/channel/lora/lorademodgui.cpp
@@ -29,6 +29,11 @@ void LoRaDemodGUI::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString LoRaDemodGUI::getName() const
+{
+	return objectName();
+}
+
 void LoRaDemodGUI::resetToDefaults()
 {
 	ui->BW->setValue(0);
diff --git a/plugins/channel/lora/lorademodgui.h b/plugins/channel/lora/lorademodgui.h
index 64d6a116a..a0ec12a7b 100644
--- a/plugins/channel/lora/lorademodgui.h
+++ b/plugins/channel/lora/lorademodgui.h
@@ -25,6 +25,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serialize() const;
diff --git a/plugins/channel/nfm/nfmdemodgui.cpp b/plugins/channel/nfm/nfmdemodgui.cpp
index fe97a7d6e..3533a6c90 100644
--- a/plugins/channel/nfm/nfmdemodgui.cpp
+++ b/plugins/channel/nfm/nfmdemodgui.cpp
@@ -33,6 +33,11 @@ void NFMDemodGUI::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString NFMDemodGUI::getName() const
+{
+	return objectName();
+}
+
 void NFMDemodGUI::resetToDefaults()
 {
 	ui->rfBW->setValue(4);
diff --git a/plugins/channel/nfm/nfmdemodgui.h b/plugins/channel/nfm/nfmdemodgui.h
index ae927add1..67319efb7 100644
--- a/plugins/channel/nfm/nfmdemodgui.h
+++ b/plugins/channel/nfm/nfmdemodgui.h
@@ -25,6 +25,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serialize() const;
diff --git a/plugins/channel/ssb/ssbdemodgui.cpp b/plugins/channel/ssb/ssbdemodgui.cpp
index ba72d47b3..6dae073d0 100644
--- a/plugins/channel/ssb/ssbdemodgui.cpp
+++ b/plugins/channel/ssb/ssbdemodgui.cpp
@@ -31,6 +31,11 @@ void SSBDemodGUI::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString SSBDemodGUI::getName() const
+{
+	return objectName();
+}
+
 void SSBDemodGUI::resetToDefaults()
 {
 	ui->BW->setValue(30);
diff --git a/plugins/channel/ssb/ssbdemodgui.h b/plugins/channel/ssb/ssbdemodgui.h
index 042e2582b..3cd40f6bc 100644
--- a/plugins/channel/ssb/ssbdemodgui.h
+++ b/plugins/channel/ssb/ssbdemodgui.h
@@ -25,6 +25,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serialize() const;
diff --git a/plugins/channel/tcpsrc/tcpsrcgui.cpp b/plugins/channel/tcpsrc/tcpsrcgui.cpp
index 5d8c91ebe..e92315e3d 100644
--- a/plugins/channel/tcpsrc/tcpsrcgui.cpp
+++ b/plugins/channel/tcpsrc/tcpsrcgui.cpp
@@ -24,6 +24,11 @@ void TCPSrcGUI::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString TCPSrcGUI::getName() const
+{
+	return objectName();
+}
+
 void TCPSrcGUI::resetToDefaults()
 {
 	ui->sampleFormat->setCurrentIndex(0);
diff --git a/plugins/channel/tcpsrc/tcpsrcgui.h b/plugins/channel/tcpsrc/tcpsrcgui.h
index 9d539fd2e..881658c25 100644
--- a/plugins/channel/tcpsrc/tcpsrcgui.h
+++ b/plugins/channel/tcpsrc/tcpsrcgui.h
@@ -25,6 +25,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serialize() const;
diff --git a/plugins/channel/wfm/wfmdemodgui.cpp b/plugins/channel/wfm/wfmdemodgui.cpp
index a0cec29df..0511f00ca 100644
--- a/plugins/channel/wfm/wfmdemodgui.cpp
+++ b/plugins/channel/wfm/wfmdemodgui.cpp
@@ -43,6 +43,11 @@ void WFMDemodGUI::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString WFMDemodGUI::getName() const
+{
+	return objectName();
+}
+
 void WFMDemodGUI::resetToDefaults()
 {
 	ui->rfBW->setValue(4);
diff --git a/plugins/channel/wfm/wfmdemodgui.h b/plugins/channel/wfm/wfmdemodgui.h
index ec0a96a88..c3f8123e7 100644
--- a/plugins/channel/wfm/wfmdemodgui.h
+++ b/plugins/channel/wfm/wfmdemodgui.h
@@ -25,6 +25,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serialize() const;
diff --git a/plugins/samplesource/CMakeLists.txt b/plugins/samplesource/CMakeLists.txt
index e48d7b8b6..6c9de667d 100644
--- a/plugins/samplesource/CMakeLists.txt
+++ b/plugins/samplesource/CMakeLists.txt
@@ -1,14 +1,6 @@
 project(samplesource)
 
 find_package(LibUSB)
-#find_package(LibOsmoSDR)
-
-add_subdirectory(gnuradio)
-#add_subdirectory(remote)
-
-#if(LIBUSB_FOUND AND LIBOSMOSDR_FOUND)
-#	add_subdirectory(osmosdr)
-#endif(LIBUSB_FOUND AND LIBOSMOSDR_FOUND)
 
 if(V4L-RTL)
 	FIND_LIBRARY (LIBV4L2 v4l2)
@@ -34,3 +26,8 @@ if(LIBUSB_FOUND AND LIBRTLSDR_FOUND)
 	add_subdirectory(rtlsdr)
 endif(LIBUSB_FOUND AND LIBRTLSDR_FOUND)
 
+find_package(LibBLADERF)
+if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
+	add_subdirectory(bladerf)
+endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
+
diff --git a/plugins/samplesource/bladerf/CMakeLists.txt b/plugins/samplesource/bladerf/CMakeLists.txt
new file mode 100644
index 000000000..3c7a3bc0f
--- /dev/null
+++ b/plugins/samplesource/bladerf/CMakeLists.txt
@@ -0,0 +1,50 @@
+project(bladerf)
+
+set(bladerf_SOURCES
+	bladerfgui.cpp
+	bladerfinput.cpp
+	bladerfplugin.cpp
+	bladerfthread.cpp
+)
+
+set(bladerf_HEADERS
+	bladerfgui.h
+	bladerfinput.h
+	bladerfplugin.h
+	bladerfthread.h
+)
+
+set(bladerf_FORMS
+	bladerfgui.ui
+)
+
+include_directories(
+	.
+	${CMAKE_CURRENT_BINARY_DIR}
+	${CMAKE_SOURCE_DIR}/include
+	${CMAKE_SOURCE_DIR}/include-gpl
+	${LIBRTLSDR_INCLUDE_DIR}
+)
+
+#include(${QT_USE_FILE})
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+
+#qt4_wrap_cpp(bladerf_HEADERS_MOC ${bladerf_HEADERS})
+qt5_wrap_ui(bladerf_FORMS_HEADERS ${bladerf_FORMS})
+
+add_library(inputbladerf SHARED
+	${bladerf_SOURCES}
+	${bladerf_HEADERS_MOC}
+	${bladerf_FORMS_HEADERS}
+)
+
+target_link_libraries(inputbladerf
+	${QT_LIBRARIES}
+	${LIBBLADERF_LIBRARIES}
+	${LIBUSB_LIBRARIES}
+	sdrbase
+)
+
+qt5_use_modules(inputbladerf Core Widgets OpenGL Multimedia)
diff --git a/plugins/samplesource/bladerf/bladerfgui.cpp b/plugins/samplesource/bladerf/bladerfgui.cpp
new file mode 100644
index 000000000..90b451a9a
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfgui.cpp
@@ -0,0 +1,356 @@
+#include <iostream>
+#include <libbladeRF.h>
+
+#include "ui_bladerfgui.h"
+#include "plugin/pluginapi.h"
+#include "bladerfgui.h"
+
+BladerfGui::BladerfGui(PluginAPI* pluginAPI, QWidget* parent) :
+	QWidget(parent),
+	ui(new Ui::BladerfGui),
+	m_pluginAPI(pluginAPI),
+	m_settings(),
+	m_sampleSource(NULL)
+{
+	ui->setupUi(this);
+	ui->centerFrequency->setValueRange(7, BLADERF_FREQUENCY_MIN/1000, BLADERF_FREQUENCY_MAX/1000);
+	connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
+	displaySettings();
+
+	m_sampleSource = new BladerfInput(m_pluginAPI->getMainWindowMessageQueue());
+	m_pluginAPI->setSampleSource(m_sampleSource);
+}
+
+BladerfGui::~BladerfGui()
+{
+	delete ui;
+}
+
+void BladerfGui::destroy()
+{
+	delete this;
+}
+
+void BladerfGui::setName(const QString& name)
+{
+	setObjectName(name);
+}
+
+QString BladerfGui::getName() const
+{
+	return objectName();
+}
+
+void BladerfGui::resetToDefaults()
+{
+	m_generalSettings.resetToDefaults();
+	m_settings.resetToDefaults();
+	displaySettings();
+	sendSettings();
+}
+
+QByteArray BladerfGui::serializeGeneral() const
+{
+	return m_generalSettings.serialize();
+}
+
+bool BladerfGui::deserializeGeneral(const QByteArray&data)
+{
+	if(m_generalSettings.deserialize(data)) {
+		displaySettings();
+		sendSettings();
+		return true;
+	} else {
+		resetToDefaults();
+		return false;
+	}
+}
+
+quint64 BladerfGui::getCenterFrequency() const
+{
+	return m_generalSettings.m_centerFrequency;
+}
+
+QByteArray BladerfGui::serialize() const
+{
+	return m_settings.serialize();
+}
+
+bool BladerfGui::deserialize(const QByteArray& data)
+{
+	if(m_settings.deserialize(data)) {
+		displaySettings();
+		sendSettings();
+		return true;
+	} else {
+		resetToDefaults();
+		return false;
+	}
+}
+
+bool BladerfGui::handleMessage(Message* message)
+{
+	if(BladerfInput::MsgReportBladerf::match(message)) {
+		displaySettings();
+		message->completed();
+		return true;
+	} else {
+		return false;
+	}
+}
+
+void BladerfGui::displaySettings()
+{
+	ui->centerFrequency->setValue(m_generalSettings.m_centerFrequency / 1000);
+
+	ui->samplerateText->setText(tr("%1k").arg(m_settings.m_samplerate / 1000));
+	unsigned int sampleRateIndex = BladerfSampleRates::getRateIndex(m_settings.m_samplerate);
+	ui->samplerate->setValue(sampleRateIndex);
+
+	ui->bandwidthText->setText(tr("%1k").arg(m_settings.m_bandwidth / 1000));
+	unsigned int bandwidthIndex = BladerfBandwidths::getBandwidthIndex(m_settings.m_bandwidth);
+	ui->bandwidth->setValue(bandwidthIndex);
+
+	ui->decimText->setText(tr("%1").arg(1<<m_settings.m_log2Decim));
+	ui->decim->setValue(m_settings.m_log2Decim);
+
+	ui->lnaGainText->setText(tr("%1").arg(m_settings.m_lnaGain));
+	ui->lna->setValue(m_settings.m_lnaGain);
+
+	ui->vga1Text->setText(tr("%1").arg(m_settings.m_vga1));
+	ui->vga1->setValue(m_settings.m_vga1);
+
+	ui->vga2Text->setText(tr("%1").arg(m_settings.m_vga2));
+	ui->vga2->setValue(m_settings.m_vga2);
+
+	ui->xb200->setCurrentIndex(getXb200Index(m_settings.m_xb200, m_settings.m_xb200Path, m_settings.m_xb200Filter));
+}
+
+void BladerfGui::sendSettings()
+{
+	if(!m_updateTimer.isActive())
+		m_updateTimer.start(100);
+}
+
+void BladerfGui::on_centerFrequency_changed(quint64 value)
+{
+	m_generalSettings.m_centerFrequency = value * 1000;
+	sendSettings();
+}
+
+void BladerfGui::on_samplerate_valueChanged(int value)
+{
+	int newrate = BladerfSampleRates::getRate(value);
+	ui->samplerateText->setText(tr("%1k").arg(newrate));
+	m_settings.m_samplerate = newrate * 1000;
+	sendSettings();
+}
+
+void BladerfGui::on_bandwidth_valueChanged(int value)
+{
+	int newbw = BladerfBandwidths::getBandwidth(value);
+	ui->bandwidthText->setText(tr("%1k").arg(newbw));
+	m_settings.m_bandwidth = newbw * 1000;
+	sendSettings();
+}
+
+void BladerfGui::on_decim_valueChanged(int value)
+{
+	if ((value <0) || (value > 4))
+		return;
+	ui->decimText->setText(tr("%1").arg(1<<value));
+	m_settings.m_log2Decim = value;
+	sendSettings();
+}
+
+void BladerfGui::on_lna_valueChanged(int value)
+{
+	std::cerr << "BladerfGui: LNA gain = " << value << std::endl;
+
+	if ((value < 0) || (value > 2))
+		return;
+
+	ui->lnaGainText->setText(tr("%1k").arg(value));
+	m_settings.m_lnaGain = value;
+	sendSettings();
+}
+
+void BladerfGui::on_vga1_valueChanged(int value)
+{
+	if ((value < BLADERF_RXVGA1_GAIN_MIN) || (value > BLADERF_RXVGA1_GAIN_MAX))
+		return;
+
+	ui->vga1Text->setText(tr("%1").arg(value));
+	m_settings.m_vga1 = value;
+	sendSettings();
+}
+
+void BladerfGui::on_vga2_valueChanged(int value)
+{
+	if ((value < BLADERF_RXVGA2_GAIN_MIN) || (value > BLADERF_RXVGA2_GAIN_MAX))
+		return;
+
+	ui->vga2Text->setText(tr("%1").arg(value));
+	m_settings.m_vga2 = value;
+	sendSettings();
+}
+
+void BladerfGui::on_xb200_currentIndexChanged(int index)
+{
+	if (index == 1) // bypass
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_BYPASS;
+	}
+	else if (index == 2) // Auto 1dB
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_MIX;
+		m_settings.m_xb200Filter = BLADERF_XB200_AUTO_1DB;
+	}
+	else if (index == 3) // Auto 3dB
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_MIX;
+		m_settings.m_xb200Filter = BLADERF_XB200_AUTO_3DB;
+	}
+	else if (index == 4) // Custom
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_MIX;
+		m_settings.m_xb200Filter = BLADERF_XB200_CUSTOM;
+	}
+	else if (index == 5) // 50 MHz
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_MIX;
+		m_settings.m_xb200Filter = BLADERF_XB200_50M;
+	}
+	else if (index == 6) // 144 MHz
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_MIX;
+		m_settings.m_xb200Filter = BLADERF_XB200_144M;
+	}
+	else if (index == 7) // 222 MHz
+	{
+		m_settings.m_xb200 = true;
+		m_settings.m_xb200Path = BLADERF_XB200_MIX;
+		m_settings.m_xb200Filter = BLADERF_XB200_222M;
+	}
+	else // no xb200
+	{
+		m_settings.m_xb200 = false;
+	}
+
+	sendSettings();
+}
+
+void BladerfGui::updateHardware()
+{
+	BladerfInput::MsgConfigureBladerf* message = BladerfInput::MsgConfigureBladerf::create(m_generalSettings, m_settings);
+	message->submit(m_pluginAPI->getDSPEngineMessageQueue());
+	m_updateTimer.stop();
+}
+
+unsigned int BladerfGui::getXb200Index(bool xb_200, bladerf_xb200_path xb200Path, bladerf_xb200_filter xb200Filter)
+{
+	if (xb_200)
+	{
+		if (xb200Path == BLADERF_XB200_BYPASS)
+		{
+			return 1;
+		}
+		else
+		{
+			if (xb200Filter == BLADERF_XB200_AUTO_1DB)
+			{
+				return 2;
+			}
+			else if (xb200Filter == BLADERF_XB200_AUTO_3DB)
+			{
+				return 3;
+			}
+			else if (xb200Filter == BLADERF_XB200_CUSTOM)
+			{
+				return 4;
+			}
+			else if (xb200Filter == BLADERF_XB200_50M)
+			{
+				return 5;
+			}
+			else if (xb200Filter == BLADERF_XB200_144M)
+			{
+				return 6;
+			}
+			else if (xb200Filter == BLADERF_XB200_222M)
+			{
+				return 7;
+			}
+			else
+			{
+				return 0;
+			}
+		}
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+unsigned int BladerfSampleRates::m_rates[] = {384, 768, 1536, 2304, 3072, 6144, 12288, 24576, 30720, 39936};
+unsigned int BladerfSampleRates::m_nb_rates = 10;
+
+unsigned int BladerfSampleRates::getRate(unsigned int rate_index)
+{
+	if (rate_index < m_nb_rates)
+	{
+		return m_rates[rate_index];
+	}
+	else
+	{
+		return m_rates[0];
+	}
+}
+
+unsigned int BladerfSampleRates::getRateIndex(unsigned int rate)
+{
+	for (unsigned int i=0; i < m_nb_rates; i++)
+	{
+		if (rate/1000 == m_rates[i])
+		{
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+unsigned int BladerfBandwidths::m_halfbw[] = {750, 875, 1250, 1375, 1500, 1920, 2500, 2750, 3000, 3500, 4375, 5000, 6000, 7000, 10000, 14000};
+unsigned int BladerfBandwidths::m_nb_halfbw = 16;
+
+unsigned int BladerfBandwidths::getBandwidth(unsigned int bandwidth_index)
+{
+	if (bandwidth_index < m_nb_halfbw)
+	{
+		return m_halfbw[bandwidth_index] * 2;
+	}
+	else
+	{
+		return m_halfbw[0] * 2;
+	}
+}
+
+unsigned int BladerfBandwidths::getBandwidthIndex(unsigned int bandwidth)
+{
+	for (unsigned int i=0; i < m_nb_halfbw; i++)
+	{
+		if (bandwidth/2 == m_halfbw[i])
+		{
+			return i;
+		}
+	}
+
+	return 0;
+}
diff --git a/plugins/samplesource/bladerf/bladerfgui.h b/plugins/samplesource/bladerf/bladerfgui.h
new file mode 100644
index 000000000..26059a864
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfgui.h
@@ -0,0 +1,79 @@
+#ifndef INCLUDE_BLADERFGUI_H
+#define INCLUDE_BLADERFGUI_H
+
+#include <QTimer>
+#include "plugin/plugingui.h"
+
+#include "bladerfinput.h"
+
+class PluginAPI;
+
+namespace Ui {
+	class BladerfGui;
+	class BladerfSampleRates;
+}
+
+class BladerfGui : public QWidget, public PluginGUI {
+	Q_OBJECT
+
+public:
+	explicit BladerfGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
+	~BladerfGui();
+	void destroy();
+
+	void setName(const QString& name);
+	QString getName() const;
+
+	void resetToDefaults();
+	QByteArray serializeGeneral() const;
+	bool deserializeGeneral(const QByteArray&data);
+	quint64 getCenterFrequency() const;
+	QByteArray serialize() const;
+	bool deserialize(const QByteArray& data);
+	bool handleMessage(Message* message);
+
+private:
+	Ui::BladerfGui* ui;
+
+	PluginAPI* m_pluginAPI;
+	SampleSource::GeneralSettings m_generalSettings;
+	BladerfInput::Settings m_settings;
+	QTimer m_updateTimer;
+	std::vector<int> m_gains;
+	SampleSource* m_sampleSource;
+
+	void displaySettings();
+	void sendSettings();
+	unsigned int getXb200Index(bool xb_200, bladerf_xb200_path xb200Path, bladerf_xb200_filter xb200Filter);
+
+private slots:
+	void on_centerFrequency_changed(quint64 value);
+	void on_samplerate_valueChanged(int value);
+	void on_bandwidth_valueChanged(int value);
+	void on_decim_valueChanged(int value);
+	void on_lna_valueChanged(int value);
+	void on_vga1_valueChanged(int value);
+	void on_vga2_valueChanged(int value);
+	void on_xb200_currentIndexChanged(int index);
+	void updateHardware();
+};
+
+class BladerfSampleRates {
+public:
+	static unsigned int getRate(unsigned int rate_index);
+	static unsigned int getRateIndex(unsigned int rate);
+private:
+	static unsigned int m_rates[10];
+	static unsigned int m_nb_rates;
+};
+
+class BladerfBandwidths {
+public:
+	static unsigned int getBandwidth(unsigned int bandwidth_index);
+	static unsigned int getBandwidthIndex(unsigned int bandwidth);
+private:
+	static unsigned int m_halfbw[16];
+	static unsigned int m_nb_halfbw;
+};
+
+#endif // INCLUDE_BLADERFGUI_H
diff --git a/plugins/samplesource/bladerf/bladerfgui.ui b/plugins/samplesource/bladerf/bladerfgui.ui
new file mode 100644
index 000000000..6f6af9e61
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfgui.ui
@@ -0,0 +1,556 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BladerfGui</class>
+ <widget class="QWidget" name="BladerfGui">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>198</width>
+    <height>255</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>BladeRF</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>3</number>
+   </property>
+   <property name="leftMargin">
+    <number>2</number>
+   </property>
+   <property name="topMargin">
+    <number>2</number>
+   </property>
+   <property name="rightMargin">
+    <number>2</number>
+   </property>
+   <property name="bottomMargin">
+    <number>2</number>
+   </property>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_freq">
+     <item>
+      <spacer name="freqLeftSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>0</width>
+         <height>0</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="ValueDial" name="centerFrequency" native="true">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>32</width>
+         <height>16</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <family>Monospace</family>
+         <pointsize>20</pointsize>
+        </font>
+       </property>
+       <property name="cursor">
+        <cursorShape>SizeVerCursor</cursorShape>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::StrongFocus</enum>
+       </property>
+       <property name="toolTip">
+        <string>Tuner center frequency in kHz</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="freqRightlSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>0</width>
+         <height>0</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_freq">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_xb200">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="2">
+      <spacer name="xb200Spacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item row="0" column="1">
+      <widget class="QComboBox" name="xb200">
+       <property name="currentText">
+        <string>None</string>
+       </property>
+       <property name="currentIndex">
+        <number>0</number>
+       </property>
+       <property name="maxVisibleItems">
+        <number>5</number>
+       </property>
+       <item>
+        <property name="text">
+         <string>None</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Bypass</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Auto 1dB</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Auto 3dB</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Custom</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>50M</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>144M</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>222M</string>
+        </property>
+       </item>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="xb200Label">
+       <property name="text">
+        <string>xb200</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_dial">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_samplerate">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="1">
+      <widget class="QSlider" name="samplerate">
+       <property name="toolTip">
+        <string>Device Samplerate</string>
+       </property>
+       <property name="maximum">
+        <number>9</number>
+       </property>
+       <property name="pageStep">
+        <number>1</number>
+       </property>
+       <property name="value">
+        <number>3</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="samplerateLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>Rate</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="samplerateText">
+       <property name="minimumSize">
+        <size>
+         <width>40</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>---</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_rate">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_bandwidth">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="1">
+      <widget class="QSlider" name="bandwidth">
+       <property name="toolTip">
+        <string>Device Samplerate</string>
+       </property>
+       <property name="maximum">
+        <number>15</number>
+       </property>
+       <property name="pageStep">
+        <number>1</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="bandwidthLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>BW  </string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="bandwidthText">
+       <property name="minimumSize">
+        <size>
+         <width>40</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>---</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_decim">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_decim" columnstretch="0,0,0">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_decim">
+       <property name="text">
+        <string>Dec.</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QSlider" name="decim">
+       <property name="maximum">
+        <number>4</number>
+       </property>
+       <property name="pageStep">
+        <number>1</number>
+       </property>
+       <property name="value">
+        <number>0</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="decimText">
+       <property name="minimumSize">
+        <size>
+         <width>40</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>1</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_bandwidth">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_lna">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="0">
+      <widget class="QLabel" name="lnaGainLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>LNA </string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QSlider" name="lna">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="toolTip">
+        <string>LNA amplification</string>
+       </property>
+       <property name="maximum">
+        <number>2</number>
+       </property>
+       <property name="pageStep">
+        <number>1</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="lnaGainText">
+       <property name="minimumSize">
+        <size>
+         <width>40</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>0</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_lna">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_vga1">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="1">
+      <widget class="QSlider" name="vga1">
+       <property name="toolTip">
+        <string>Amplifier before filtering</string>
+       </property>
+       <property name="minimum">
+        <number>5</number>
+       </property>
+       <property name="maximum">
+        <number>30</number>
+       </property>
+       <property name="pageStep">
+        <number>1</number>
+       </property>
+       <property name="value">
+        <number>20</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="vga1Text">
+       <property name="minimumSize">
+        <size>
+         <width>40</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>20</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="vga1Label">
+       <property name="text">
+        <string>VGA1</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_vga1">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_vga2" columnstretch="0,0,0">
+     <property name="spacing">
+      <number>3</number>
+     </property>
+     <item row="0" column="0">
+      <widget class="QLabel" name="vga2Label">
+       <property name="text">
+        <string>VGA2</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QSlider" name="vga2">
+       <property name="toolTip">
+        <string>Amplifier before ADC</string>
+       </property>
+       <property name="maximum">
+        <number>30</number>
+       </property>
+       <property name="pageStep">
+        <number>1</number>
+       </property>
+       <property name="value">
+        <number>9</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="vga2Text">
+       <property name="minimumSize">
+        <size>
+         <width>40</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>9</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_vga2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ValueDial</class>
+   <extends>QWidget</extends>
+   <header>gui/valuedial.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/plugins/samplesource/bladerf/bladerfinput.cpp b/plugins/samplesource/bladerf/bladerfinput.cpp
new file mode 100644
index 000000000..5fd243a70
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfinput.cpp
@@ -0,0 +1,392 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
+// written by Christian Daniel                                                   //
+//                                                                               //
+// This program is free software; you can redistribute it and/or modify          //
+// it under the terms of the GNU General Public License as published by          //
+// the Free Software Foundation as version 3 of the License, or                  //
+//                                                                               //
+// This program is distributed in the hope that it will be useful,               //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
+// GNU General Public License V3 for more details.                               //
+//                                                                               //
+// You should have received a copy of the GNU General Public License             //
+// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <string.h>
+#include <errno.h>
+#include <cstdio>
+#include <iostream>
+
+#include "util/simpleserializer.h"
+#include "bladerfgui.h"
+#include "bladerfinput.h"
+#include "bladerfthread.h"
+
+MESSAGE_CLASS_DEFINITION(BladerfInput::MsgConfigureBladerf, Message)
+MESSAGE_CLASS_DEFINITION(BladerfInput::MsgReportBladerf, Message)
+
+BladerfInput::Settings::Settings() :
+	m_lnaGain(0),
+	m_vga1(20),
+	m_vga2(9),
+	m_samplerate(2400000),
+	m_bandwidth(1500000),
+	m_log2Decim(0),
+	m_xb200(false),
+	m_xb200Path(BLADERF_XB200_MIX),
+	m_xb200Filter(BLADERF_XB200_AUTO_1DB)
+{
+}
+
+void BladerfInput::Settings::resetToDefaults()
+{
+	m_lnaGain = 0;
+	m_vga1 = 20;
+	m_vga2 = 9;
+	m_samplerate = 2400000;
+	m_log2Decim = 0;
+	m_xb200 = false;
+	m_xb200Path = BLADERF_XB200_MIX;
+	m_xb200Filter = BLADERF_XB200_AUTO_1DB;
+}
+
+QByteArray BladerfInput::Settings::serialize() const
+{
+	SimpleSerializer s(1);
+	s.writeS32(1, m_lnaGain);
+	s.writeS32(2, m_vga1);
+	s.writeS32(3, m_vga2);
+	s.writeS32(4, m_samplerate);
+	s.writeU32(5, m_log2Decim);
+	s.writeBool(6, m_xb200);
+	s.writeS32(7, (int) m_xb200Path);
+	s.writeS32(8, (int) m_xb200Filter);
+	return s.final();
+}
+
+bool BladerfInput::Settings::deserialize(const QByteArray& data)
+{
+	SimpleDeserializer d(data);
+
+	if(!d.isValid()) {
+		resetToDefaults();
+		return false;
+	}
+
+	if(d.getVersion() == 1) {
+		int intval;
+		d.readS32(1, &m_lnaGain, 0);
+		d.readS32(2, &m_vga1, 20);
+		d.readS32(3, &m_vga2, 9);
+		d.readS32(4, &m_samplerate, 0);
+		d.readU32(5, &m_log2Decim, 4);
+		d.readBool(6, &m_xb200);
+		d.readS32(7, &intval);
+		m_xb200Path = (bladerf_xb200_path) intval;
+		d.readS32(8, &intval);
+		m_xb200Filter = (bladerf_xb200_filter) intval;
+		return true;
+	} else {
+		resetToDefaults();
+		return false;
+	}
+}
+
+BladerfInput::BladerfInput(MessageQueue* msgQueueToGUI) :
+	SampleSource(msgQueueToGUI),
+	m_settings(),
+	m_dev(NULL),
+	m_bladerfThread(NULL),
+	m_deviceDescription()
+{
+}
+
+BladerfInput::~BladerfInput()
+{
+	stopInput();
+}
+
+bool BladerfInput::startInput(int device)
+{
+	QMutexLocker mutexLocker(&m_mutex);
+
+	if(m_dev != NULL)
+		stopInput();
+
+	int res;
+	int fpga_loaded;
+
+	if(!m_sampleFifo.setSize(96000 * 4)) {
+		qCritical("Could not allocate SampleFifo");
+		return false;
+	}
+
+	if ((m_dev = open_bladerf_from_serial(0)) == NULL) // TODO: fix; Open first available device as there is no proper handling for multiple devices
+	{
+		qCritical("could not open BladeRF");
+		return false;
+	}
+
+    fpga_loaded = bladerf_is_fpga_configured(m_dev);
+
+    if (fpga_loaded < 0) {
+    	qCritical("Failed to check FPGA state: %s",
+                  bladerf_strerror(fpga_loaded));
+    	return false;
+    } else if (fpga_loaded == 0) {
+    	qCritical("The device's FPGA is not loaded.");
+    	return false;
+    }
+
+    // TODO: adjust USB transfer data according to sample rate
+    if ((res = bladerf_sync_config(m_dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000)) < 0)
+    {
+    	qCritical("bladerf_sync_config with return code %d", res);
+    	goto failed;
+    }
+
+    if ((res = bladerf_enable_module(m_dev, BLADERF_MODULE_RX, true)) < 0)
+    {
+    	qCritical("bladerf_enable_module with return code %d", res);
+    	goto failed;
+    }
+
+	if((m_bladerfThread = new BladerfThread(m_dev, &m_sampleFifo)) == NULL) {
+		qFatal("out of memory");
+		goto failed;
+	}
+
+	m_bladerfThread->startWork();
+
+	mutexLocker.unlock();
+	applySettings(m_generalSettings, m_settings, true);
+
+	qDebug("bladerfInput: start");
+	//MsgReportBladerf::create(m_gains)->submit(m_guiMessageQueue); Pass anything here
+
+	return true;
+
+failed:
+	stopInput();
+	return false;
+}
+
+void BladerfInput::stopInput()
+{
+	QMutexLocker mutexLocker(&m_mutex);
+
+	if(m_bladerfThread != NULL) {
+		m_bladerfThread->stopWork();
+		delete m_bladerfThread;
+		m_bladerfThread = NULL;
+	}
+	if(m_dev != NULL) {
+		bladerf_close(m_dev);
+		m_dev = NULL;
+	}
+	m_deviceDescription.clear();
+}
+
+const QString& BladerfInput::getDeviceDescription() const
+{
+	return m_deviceDescription;
+}
+
+int BladerfInput::getSampleRate() const
+{
+	int rate = m_settings.m_samplerate;
+	return (rate / (1<<m_settings.m_log2Decim));
+}
+
+quint64 BladerfInput::getCenterFrequency() const
+{
+	return m_generalSettings.m_centerFrequency;
+}
+
+bool BladerfInput::handleMessage(Message* message)
+{
+	if(MsgConfigureBladerf::match(message)) {
+		MsgConfigureBladerf* conf = (MsgConfigureBladerf*)message;
+		if(!applySettings(conf->getGeneralSettings(), conf->getSettings(), false))
+			qDebug("BladeRF config error");
+		message->completed();
+		return true;
+	} else {
+		return false;
+	}
+}
+
+bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force)
+{
+	QMutexLocker mutexLocker(&m_mutex);
+
+	if((m_settings.m_lnaGain != settings.m_lnaGain) || force) {
+		m_settings.m_lnaGain = settings.m_lnaGain;
+		if(m_dev != NULL) {
+			if(bladerf_set_lna_gain(m_dev, getLnaGain(m_settings.m_lnaGain)) != 0) {
+				qDebug("bladerf_set_lna_gain() failed");
+			} else {
+				std::cerr << "BladerfInput: LNA gain set to " << getLnaGain(m_settings.m_lnaGain) << std::endl;
+			}
+		}
+	}
+
+	if((m_settings.m_vga1 != settings.m_vga1) || force) {
+		m_settings.m_vga1 = settings.m_vga1;
+		if(m_dev != NULL) {
+			if(bladerf_set_rxvga1(m_dev, m_settings.m_vga1) != 0) {
+				qDebug("bladerf_set_rxvga1() failed");
+			} else {
+				std::cerr << "BladerfInput: VGA1 gain set to " << m_settings.m_vga1 << std::endl;
+			}
+		}
+	}
+
+	if((m_settings.m_vga2 != settings.m_vga2) || force) {
+		m_settings.m_vga2 = settings.m_vga2;
+		if(m_dev != NULL) {
+			if(bladerf_set_rxvga2(m_dev, m_settings.m_vga2) != 0) {
+				qDebug("bladerf_set_rxvga2() failed");
+			} else {
+				std::cerr << "BladerfInput: VGA2 gain set to " << m_settings.m_vga2 << std::endl;
+			}
+		}
+	}
+
+	if((m_settings.m_xb200 != settings.m_xb200) || force) {
+		m_settings.m_xb200 = settings.m_xb200;
+		if(m_dev != NULL) {
+			if (m_settings.m_xb200) {
+				if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0) {
+					qDebug("bladerf_expansion_attach(xb200) failed");
+				} else {
+					std::cerr << "BladerfInput: Attach XB200" << std::endl;
+				}
+			} else {
+				if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0) {
+					qDebug("bladerf_expansion_attach(none) failed");
+				} else {
+					std::cerr << "BladerfInput: Detach XB200" << std::endl;
+				}
+			}
+		}
+	}
+
+	if((m_settings.m_xb200Path != settings.m_xb200Path) || force) {
+		m_settings.m_xb200Path = settings.m_xb200Path;
+		if(m_dev != NULL) {
+			if(bladerf_xb200_set_path(m_dev, BLADERF_MODULE_RX, m_settings.m_xb200Path) != 0) {
+				qDebug("bladerf_xb200_set_path(BLADERF_MODULE_RX) failed");
+			} else {
+				std::cerr << "BladerfInput: set xb200 path to " << m_settings.m_xb200Path << std::endl;
+			}
+		}
+	}
+
+	if((m_settings.m_xb200Filter != settings.m_xb200Filter) || force) {
+		m_settings.m_xb200Filter = settings.m_xb200Filter;
+		if(m_dev != NULL) {
+			if(bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_RX, m_settings.m_xb200Filter) != 0) {
+				qDebug("bladerf_xb200_set_filterbank(BLADERF_MODULE_RX) failed");
+			} else {
+				std::cerr << "BladerfInput: set xb200 filter to " << m_settings.m_xb200Filter << std::endl;
+			}
+		}
+	}
+
+	if((m_settings.m_samplerate != settings.m_samplerate) || force) {
+		if(m_dev != NULL) {
+			unsigned int actualSamplerate;
+			if( bladerf_set_sample_rate(m_dev, BLADERF_MODULE_RX, settings.m_samplerate, &actualSamplerate) < 0)
+				qCritical("could not set sample rate: %d", settings.m_samplerate);
+			else {
+				std::cerr << "bladerf_set_sample_rate(BLADERF_MODULE_RX) actual sample rate is " << actualSamplerate << std::endl;
+				m_settings.m_samplerate = settings.m_samplerate;
+				m_bladerfThread->setSamplerate(settings.m_samplerate);
+			}
+		}
+	}
+
+	if((m_settings.m_bandwidth != settings.m_bandwidth) || force) {
+		if(m_dev != NULL) {
+			unsigned int actualBandwidth;
+			if( bladerf_set_bandwidth(m_dev, BLADERF_MODULE_RX, settings.m_bandwidth, &actualBandwidth) < 0)
+				qCritical("could not set sample rate: %d", settings.m_samplerate);
+			else {
+				std::cerr << "bladerf_set_bandwidth(BLADERF_MODULE_RX) actual bandwidth is " << actualBandwidth << std::endl;
+				m_settings.m_bandwidth = settings.m_bandwidth;
+			}
+		}
+	}
+
+	if((m_settings.m_log2Decim != settings.m_log2Decim) || force) {
+		if(m_dev != NULL) {
+			m_settings.m_log2Decim = settings.m_log2Decim;
+			m_bladerfThread->setLog2Decimation(settings.m_log2Decim);
+		}
+	}
+
+	m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency;
+	if(m_dev != NULL) {
+		qint64 centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4);
+
+		if (m_settings.m_log2Decim == 0) { // Little wooby-doop if no decimation
+			centerFrequency = m_generalSettings.m_centerFrequency;
+		} else {
+			centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4);
+		}
+
+		if(bladerf_set_frequency( m_dev, BLADERF_MODULE_RX, centerFrequency ) != 0) {
+			qDebug("bladerf_set_frequency(%lld) failed", m_generalSettings.m_centerFrequency);
+		}
+	}
+
+	return true;
+}
+
+bladerf_lna_gain BladerfInput::getLnaGain(int lnaGain)
+{
+	if (lnaGain == 2) {
+		return BLADERF_LNA_GAIN_MAX;
+	} else if (lnaGain == 1) {
+		return BLADERF_LNA_GAIN_MID;
+	} else {
+		return BLADERF_LNA_GAIN_BYPASS;
+	}
+}
+
+struct bladerf *BladerfInput::open_bladerf_from_serial(const char *serial)
+{
+    int status;
+    struct bladerf *dev;
+    struct bladerf_devinfo info;
+
+    /* Initialize all fields to "don't care" wildcard values.
+     *
+     * Immediately passing this to bladerf_open_with_devinfo() would cause
+     * libbladeRF to open any device on any available backend. */
+    bladerf_init_devinfo(&info);
+
+    /* Specify the desired device's serial number, while leaving all other
+     * fields in the info structure wildcard values */
+    if (serial != NULL) {
+		strncpy(info.serial, serial, BLADERF_SERIAL_LENGTH - 1);
+		info.serial[BLADERF_SERIAL_LENGTH - 1] = '\0';
+    }
+
+    status = bladerf_open_with_devinfo(&dev, &info);
+
+    if (status == BLADERF_ERR_NODEV) {
+        fprintf(stderr, "No devices available with serial=%s\n", serial);
+        return NULL;
+    } else if (status != 0) {
+        fprintf(stderr, "Failed to open device with serial=%s (%s)\n",
+                serial, bladerf_strerror(status));
+        return NULL;
+    } else {
+        return dev;
+    }
+}
diff --git a/plugins/samplesource/bladerf/bladerfinput.h b/plugins/samplesource/bladerf/bladerfinput.h
new file mode 100644
index 000000000..0039ea851
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfinput.h
@@ -0,0 +1,110 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
+// written by Christian Daniel                                                   //
+//                                                                               //
+// This program is free software; you can redistribute it and/or modify          //
+// it under the terms of the GNU General Public License as published by          //
+// the Free Software Foundation as version 3 of the License, or                  //
+//                                                                               //
+// This program is distributed in the hope that it will be useful,               //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
+// GNU General Public License V3 for more details.                               //
+//                                                                               //
+// You should have received a copy of the GNU General Public License             //
+// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_BLADERFINPUT_H
+#define INCLUDE_BLADERFINPUT_H
+
+#include "dsp/samplesource/samplesource.h"
+#include <libbladeRF.h>
+#include <QString>
+
+class BladerfThread;
+
+class BladerfInput : public SampleSource {
+public:
+	struct Settings {
+		qint32 m_lnaGain;
+		qint32 m_vga1;
+		qint32 m_vga2;
+		qint32 m_samplerate;
+		qint32 m_bandwidth;
+		quint32 m_log2Decim;
+		bool m_xb200;
+		bladerf_xb200_path m_xb200Path;
+		bladerf_xb200_filter m_xb200Filter;
+
+		Settings();
+		void resetToDefaults();
+		QByteArray serialize() const;
+		bool deserialize(const QByteArray& data);
+	};
+
+	class MsgConfigureBladerf : public Message {
+		MESSAGE_CLASS_DECLARATION
+
+	public:
+		const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
+		const Settings& getSettings() const { return m_settings; }
+
+		static MsgConfigureBladerf* create(const GeneralSettings& generalSettings, const Settings& settings)
+		{
+			return new MsgConfigureBladerf(generalSettings, settings);
+		}
+
+	private:
+		GeneralSettings m_generalSettings;
+		Settings m_settings;
+
+		MsgConfigureBladerf(const GeneralSettings& generalSettings, const Settings& settings) :
+			Message(),
+			m_generalSettings(generalSettings),
+			m_settings(settings)
+		{ }
+	};
+
+	class MsgReportBladerf : public Message {
+		MESSAGE_CLASS_DECLARATION
+
+	public:
+
+		static MsgReportBladerf* create()
+		{
+			return new MsgReportBladerf();
+		}
+
+	protected:
+
+		MsgReportBladerf() :
+			Message()
+		{ }
+	};
+
+	BladerfInput(MessageQueue* msgQueueToGUI);
+	~BladerfInput();
+
+	bool startInput(int device);
+	void stopInput();
+
+	const QString& getDeviceDescription() const;
+	int getSampleRate() const;
+	quint64 getCenterFrequency() const;
+
+	bool handleMessage(Message* message);
+
+private:
+	QMutex m_mutex;
+	Settings m_settings;
+	struct bladerf* m_dev;
+	BladerfThread* m_bladerfThread;
+	QString m_deviceDescription;
+
+	bool applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force);
+	bladerf_lna_gain getLnaGain(int lnaGain);
+	struct bladerf *open_bladerf_from_serial(const char *serial);
+};
+
+#endif // INCLUDE_BLADERFINPUT_H
diff --git a/plugins/samplesource/bladerf/bladerfplugin.cpp b/plugins/samplesource/bladerf/bladerfplugin.cpp
new file mode 100644
index 000000000..974218a01
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfplugin.cpp
@@ -0,0 +1,60 @@
+#include <QtPlugin>
+#include <QAction>
+#include <libbladeRF.h>
+#include "plugin/pluginapi.h"
+#include "util/simpleserializer.h"
+#include "bladerfgui.h"
+#include "bladerfplugin.h"
+
+const PluginDescriptor BlderfPlugin::m_pluginDescriptor = {
+	QString("BladerRF Input"),
+	QString("1.0"),
+	QString("(c) Edouard Griffiths, F4EXB"),
+	QString("https://github.com/f4exb/rtl-sdrangelove/tree/f4exb"),
+	true,
+	QString("https://github.com/f4exb/rtl-sdrangelove/tree/f4exb")
+};
+
+BlderfPlugin::BlderfPlugin(QObject* parent) :
+	QObject(parent)
+{
+}
+
+const PluginDescriptor& BlderfPlugin::getPluginDescriptor() const
+{
+	return m_pluginDescriptor;
+}
+
+void BlderfPlugin::initPlugin(PluginAPI* pluginAPI)
+{
+	m_pluginAPI = pluginAPI;
+	m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.bladerf", this);
+}
+
+PluginInterface::SampleSourceDevices BlderfPlugin::enumSampleSources()
+{
+	SampleSourceDevices result;
+	struct bladerf_devinfo *devinfo;
+	int count = bladerf_get_device_list(&devinfo);
+
+	for(int i = 0; i < count; i++)
+	{
+		QString displayedName(QString("BladeRF #%1 %2 (%3,%4)").arg(devinfo[i].instance).arg(devinfo[i].serial).arg(devinfo[i].usb_bus).arg(devinfo[i].usb_addr));
+		SimpleSerializer s(1);
+		s.writeS32(1, i);
+		s.writeString(2, devinfo[i].serial);
+		result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.bladerf", s.final()));
+	}
+	return result;
+}
+
+PluginGUI* BlderfPlugin::createSampleSource(const QString& sourceName, const QByteArray& address)
+{
+	if(sourceName == "org.osmocom.sdr.samplesource.bladerf") {
+		BladerfGui* gui = new BladerfGui(m_pluginAPI);
+		m_pluginAPI->setInputGUI(gui);
+		return gui;
+	} else {
+		return NULL;
+	}
+}
diff --git a/plugins/samplesource/bladerf/bladerfplugin.h b/plugins/samplesource/bladerf/bladerfplugin.h
new file mode 100644
index 000000000..f0d49388d
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfplugin.h
@@ -0,0 +1,27 @@
+#ifndef INCLUDE_BLADERFPLUGIN_H
+#define INCLUDE_BLADERFPLUGIN_H
+
+#include <QObject>
+#include "plugin/plugininterface.h"
+
+class BlderfPlugin : public QObject, PluginInterface {
+	Q_OBJECT
+	Q_INTERFACES(PluginInterface)
+	Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.bladerf")
+
+public:
+	explicit BlderfPlugin(QObject* parent = NULL);
+
+	const PluginDescriptor& getPluginDescriptor() const;
+	void initPlugin(PluginAPI* pluginAPI);
+
+	SampleSourceDevices enumSampleSources();
+	PluginGUI* createSampleSource(const QString& sourceName, const QByteArray& address);
+
+private:
+	static const PluginDescriptor m_pluginDescriptor;
+
+	PluginAPI* m_pluginAPI;
+};
+
+#endif // INCLUDE_BLADERFPLUGIN_H
diff --git a/plugins/samplesource/bladerf/bladerfthread.cpp b/plugins/samplesource/bladerf/bladerfthread.cpp
new file mode 100644
index 000000000..9549046c2
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfthread.cpp
@@ -0,0 +1,213 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
+// written by Christian Daniel                                                   //
+//                                                                               //
+// This program is free software; you can redistribute it and/or modify          //
+// it under the terms of the GNU General Public License as published by          //
+// the Free Software Foundation as version 3 of the License, or                  //
+//                                                                               //
+// This program is distributed in the hope that it will be useful,               //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
+// GNU General Public License V3 for more details.                               //
+//                                                                               //
+// You should have received a copy of the GNU General Public License             //
+// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <errno.h>
+#include "dsp/samplefifo.h"
+#include "bladerfthread.h"
+
+
+
+BladerfThread::BladerfThread(struct bladerf* dev, SampleFifo* sampleFifo, QObject* parent) :
+	QThread(parent),
+	m_running(false),
+	m_dev(dev),
+	m_convertBuffer(BLADERF_BLOCKSIZE),
+	m_sampleFifo(sampleFifo),
+	m_samplerate(2400000),
+	m_log2Decim(0)
+{
+}
+
+BladerfThread::~BladerfThread()
+{
+	stopWork();
+}
+
+void BladerfThread::startWork()
+{
+	m_startWaitMutex.lock();
+	start();
+	while(!m_running)
+		m_startWaiter.wait(&m_startWaitMutex, 100);
+	m_startWaitMutex.unlock();
+}
+
+void BladerfThread::stopWork()
+{
+	m_running = false;
+	wait();
+}
+
+void BladerfThread::setSamplerate(int samplerate)
+{
+	m_samplerate = samplerate;
+}
+
+void BladerfThread::setLog2Decimation(unsigned int log2_decim)
+{
+	m_log2Decim = log2_decim;
+}
+
+void BladerfThread::run()
+{
+	int res;
+
+	m_running = true;
+	m_startWaiter.wakeAll();
+
+	while(m_running) {
+		if((res = bladerf_sync_rx(m_dev, m_buf, BLADERF_BLOCKSIZE, NULL, 10000)) < 0) {
+			qCritical("BladerfThread: sync error: %s", strerror(errno));
+			break;
+		}
+
+		callback(m_buf, 2 * BLADERF_BLOCKSIZE);
+	}
+
+	m_running = false;
+}
+
+void BladerfThread::decimate1(SampleVector::iterator* it, const qint16* buf, qint32 len)
+{
+	qint16 xreal, yimag;
+
+	for (int pos = 0; pos < len; pos += 2) {
+		xreal = buf[pos+0];
+		yimag = buf[pos+1];
+		Sample s( xreal * 16, yimag * 16 ); // shift by 4 bit positions (signed)
+		**it = s;
+		(*it)++;
+	}
+}
+
+void BladerfThread::decimate2_u(SampleVector::iterator* it, const quint16* buf, qint32 len)
+{
+	qint16 xreal, yimag;
+	for (int pos = 0; pos < len - 7; pos += 8) {
+		xreal = buf[pos+0] - buf[pos+3];
+		yimag = buf[pos+1] + buf[pos+2] - 255;
+		Sample s( xreal << 3, yimag << 3 );
+		**it = s;
+		(*it)++;
+		xreal = buf[pos+7] - buf[pos+4];
+		yimag = 255 - buf[pos+5] - buf[pos+6];
+		Sample t( xreal << 3, yimag << 3 );
+		**it = t;
+		(*it)++;
+	}
+}
+
+void BladerfThread::decimate2(SampleVector::iterator* it, const qint16* buf, qint32 len)
+{
+	qint16 xreal, yimag;
+	for (int pos = 0; pos < len - 7; pos += 8) {
+		xreal = buf[pos+0] - buf[pos+3];
+		yimag = buf[pos+1] + buf[pos+2];
+		Sample s( xreal << 3, yimag << 3 );
+		**it = s;
+		(*it)++;
+		xreal = buf[pos+7] - buf[pos+4];
+		yimag = - buf[pos+5] - buf[pos+6];
+		Sample t( xreal << 3, yimag << 3 );
+		**it = t;
+		(*it)++;
+	}
+}
+
+void BladerfThread::decimate4(SampleVector::iterator* it, const qint16* buf, qint32 len)
+{
+	qint16 xreal, yimag;
+		for (int pos = 0; pos < len - 7; pos += 8) {
+		xreal = buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
+		yimag = buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
+		Sample s( xreal << 2, yimag << 2 ); // was shift 3
+		**it = s;
+		(*it)++;
+	}
+}
+
+void BladerfThread::decimate8(SampleVector::iterator* it, const qint16* buf, qint32 len)
+{
+	qint16 xreal, yimag;
+	for (int pos = 0; pos < len - 15; pos += 8) {
+		xreal = buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
+		yimag = buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
+		Sample s1( xreal << 2, yimag << 2 ); // was shift 3
+		pos += 8;
+		xreal = buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4];
+		yimag = buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6];
+		Sample s2( xreal << 2, yimag << 2 ); // was shift 3
+
+		m_decimator2.myDecimate(&s1, &s2);
+		**it = s2;
+		(*it)++;
+	}
+}
+
+void BladerfThread::decimate16(SampleVector::iterator* it, const qint16* buf, qint32 len)
+{
+	// Offset tuning: 4x downsample and rotate, then
+	// downsample 4x more. [ rotate:  0, 1, -3, 2, -4, -5, 7, -6]
+	qint16 xreal[4], yimag[4];
+
+	for (int pos = 0; pos < len - 31; ) {
+		for (int i = 0; i < 4; i++) {
+			xreal[i] = (buf[pos+0] - buf[pos+3] + buf[pos+7] - buf[pos+4]) << 2; // was shift 4
+			yimag[i] = (buf[pos+1] - buf[pos+5] + buf[pos+2] - buf[pos+6]) << 2; // was shift 4
+			pos += 8;
+		}
+		Sample s1( xreal[0], yimag[0] );
+		Sample s2( xreal[1], yimag[1] );
+		Sample s3( xreal[2], yimag[2] );
+		Sample s4( xreal[3], yimag[3] );
+		m_decimator2.myDecimate(&s1, &s2);
+		m_decimator2.myDecimate(&s3, &s4);
+		m_decimator4.myDecimate(&s2, &s4);
+		**it = s4;
+		(*it)++;
+	}
+}
+
+//  Decimate according to specified log2 (ex: log2=4 => decim=16)
+void BladerfThread::callback(const qint16* buf, qint32 len)
+{
+	SampleVector::iterator it = m_convertBuffer.begin();
+
+	switch (m_log2Decim)
+	{
+	case 0:
+		decimate1(&it, buf, len);
+		break;
+	case 1:
+		decimate2(&it, buf, len);
+		break;
+	case 2:
+		decimate4(&it, buf, len);
+		break;
+	case 3:
+		decimate8(&it, buf, len);
+		break;
+	case 4:
+		decimate16(&it, buf, len);
+		break;
+	default:
+		break;
+	}
+
+	m_sampleFifo->write(m_convertBuffer.begin(), it);
+}
diff --git a/plugins/samplesource/bladerf/bladerfthread.h b/plugins/samplesource/bladerf/bladerfthread.h
new file mode 100644
index 000000000..f18b00454
--- /dev/null
+++ b/plugins/samplesource/bladerf/bladerfthread.h
@@ -0,0 +1,68 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
+// written by Christian Daniel                                                   //
+//                                                                               //
+// This program is free software; you can redistribute it and/or modify          //
+// it under the terms of the GNU General Public License as published by          //
+// the Free Software Foundation as version 3 of the License, or                  //
+//                                                                               //
+// This program is distributed in the hope that it will be useful,               //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
+// GNU General Public License V3 for more details.                               //
+//                                                                               //
+// You should have received a copy of the GNU General Public License             //
+// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_BLADERFTHREAD_H
+#define INCLUDE_BLADERFTHREAD_H
+
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <libbladeRF.h>
+#include "dsp/samplefifo.h"
+#include "dsp/inthalfbandfilter.h"
+
+#define BLADERF_BLOCKSIZE 16384
+
+class BladerfThread : public QThread {
+	Q_OBJECT
+
+public:
+	BladerfThread(struct bladerf* dev, SampleFifo* sampleFifo, QObject* parent = NULL);
+	~BladerfThread();
+
+	void startWork();
+	void stopWork();
+	void setSamplerate(int samplerate);
+	void setLog2Decimation(unsigned int log2_decim);
+
+private:
+	QMutex m_startWaitMutex;
+	QWaitCondition m_startWaiter;
+	bool m_running;
+
+	struct bladerf* m_dev;
+	qint16 m_buf[2*BLADERF_BLOCKSIZE];
+	SampleVector m_convertBuffer;
+	SampleFifo* m_sampleFifo;
+
+	int m_samplerate;
+	unsigned int m_log2Decim;
+
+	IntHalfbandFilter m_decimator2;
+	IntHalfbandFilter m_decimator4;
+
+	void run();
+	void decimate1(SampleVector::iterator* it, const qint16* buf, qint32 len);
+	void decimate2_u(SampleVector::iterator* it, const quint16* buf, qint32 len);
+	void decimate2(SampleVector::iterator* it, const qint16* buf, qint32 len);
+	void decimate4(SampleVector::iterator* it, const qint16* buf, qint32 len);
+	void decimate8(SampleVector::iterator* it, const qint16* buf, qint32 len);
+	void decimate16(SampleVector::iterator* it, const qint16* buf, qint32 len);
+	void callback(const qint16* buf, qint32 len);
+};
+
+#endif // INCLUDE_BLADERFTHREAD_H
diff --git a/plugins/samplesource/fcd/fcdgui.cpp b/plugins/samplesource/fcd/fcdgui.cpp
index e5ec71d76..dfda51a93 100644
--- a/plugins/samplesource/fcd/fcdgui.cpp
+++ b/plugins/samplesource/fcd/fcdgui.cpp
@@ -33,6 +33,11 @@ void FCDGui::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString FCDGui::getName() const
+{
+	return objectName();
+}
+
 void FCDGui::resetToDefaults()
 {
 	m_generalSettings.resetToDefaults();
diff --git a/plugins/samplesource/fcd/fcdgui.h b/plugins/samplesource/fcd/fcdgui.h
index 72b37593a..be7a50309 100644
--- a/plugins/samplesource/fcd/fcdgui.h
+++ b/plugins/samplesource/fcd/fcdgui.h
@@ -20,6 +20,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serializeGeneral() const;
diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp
index 3fa641344..577ca3943 100644
--- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp
+++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp
@@ -34,6 +34,11 @@ void RTLSDRGui::setName(const QString& name)
 	setObjectName(name);
 }
 
+QString RTLSDRGui::getName() const
+{
+	return objectName();
+}
+
 void RTLSDRGui::resetToDefaults()
 {
 	m_generalSettings.resetToDefaults();
diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.h b/plugins/samplesource/rtlsdr/rtlsdrgui.h
index a0882ce65..e392f06a1 100644
--- a/plugins/samplesource/rtlsdr/rtlsdrgui.h
+++ b/plugins/samplesource/rtlsdr/rtlsdrgui.h
@@ -21,6 +21,7 @@ public:
 	void destroy();
 
 	void setName(const QString& name);
+	QString getName() const;
 
 	void resetToDefaults();
 	QByteArray serializeGeneral() const;
diff --git a/sdrbase/dsp/samplesource/samplesource.cpp b/sdrbase/dsp/samplesource/samplesource.cpp
index dda41d060..a13e05cbe 100644
--- a/sdrbase/dsp/samplesource/samplesource.cpp
+++ b/sdrbase/dsp/samplesource/samplesource.cpp
@@ -18,6 +18,8 @@
 #include "dsp/samplesource/samplesource.h"
 #include "util/simpleserializer.h"
 
+#include <iostream>
+
 SampleSource::GeneralSettings::GeneralSettings() :
 	m_centerFrequency(100000000)
 {
@@ -40,12 +42,15 @@ bool SampleSource::GeneralSettings::deserialize(const QByteArray& data)
 	SimpleDeserializer d(data);
 
 	if(!d.isValid()) {
+		std::cerr << "SampleSource::GeneralSettings::deserialize: invalid deserializer" << std::endl;
 		resetToDefaults();
 		return false;
 	}
 
 	if(d.getVersion() == 1) {
 		d.readU64(1, &m_centerFrequency, 100000000);
+		std::cerr << "SampleSource::GeneralSettings::deserialize: center frequency = "
+				<< m_centerFrequency << std::endl;
 		return true;
 	} else {
 		resetToDefaults();
diff --git a/sdrbase/mainwindow.cpp b/sdrbase/mainwindow.cpp
index 06def4656..d427a3330 100644
--- a/sdrbase/mainwindow.cpp
+++ b/sdrbase/mainwindow.cpp
@@ -36,6 +36,8 @@
 #include "plugin/pluginapi.h"
 #include "plugin/plugingui.h"
 
+#include <iostream>
+
 MainWindow::MainWindow(QWidget* parent) :
 	QMainWindow(parent),
 	ui(new Ui::MainWindow),
@@ -174,22 +176,29 @@ void MainWindow::setInputGUI(QWidget* gui)
 
 void MainWindow::loadSettings()
 {
-	m_settings.load();
+	std::cerr << "MainWindow::loadSettings" << std::endl;
+    m_settings.load();
 
-	for(int i = 0; i < m_settings.getPresetCount(); ++i)
-		addPresetToTree(m_settings.getPreset(i));
+    for(int i = 0; i < m_settings.getPresetCount(); ++i)
+    {
+    	addPresetToTree(m_settings.getPreset(i));
+    }
 
-	Preset* current = m_settings.getCurrent();
+    Preset* current = m_settings.getCurrent();
 
-	loadSettings(current);
+    loadSettings(current);
 }
 
 void MainWindow::loadSettings(const Preset* preset)
 {
-	if(preset->getShowScope()) {
+	std::cerr << "MainWindow::loadSettings(preset): " << preset->getSource().toStdString() << std::endl;
+
+	if(preset->getShowScope())
+	{
 		on_action_Oscilloscope_triggered();
 		m_scopeWindow->deserialize(preset->getScopeConfig());
-	}
+    }
+
 	ui->glSpectrumGUI->deserialize(preset->getSpectrumConfig());
 	ui->dcOffset->setChecked(preset->getDCOffsetCorrection());
 	ui->iqImbalance->setChecked(preset->getIQImbalanceCorrection());
@@ -202,21 +211,32 @@ void MainWindow::loadSettings(const Preset* preset)
 
 void MainWindow::saveSettings()
 {
+	std::cerr << "MainWindow::saveSettings" << std::endl;
+
 	saveSettings(m_settings.getCurrent());
 	m_settings.save();
+
 }
 
 void MainWindow::saveSettings(Preset* preset)
 {
+	std::cerr << "MainWindow::saveSettings(preset): " << preset->getSource().toStdString() << std::endl;
+
 	preset->setSpectrumConfig(ui->glSpectrumGUI->serialize());
+
 	if(preset->getShowScope())
+	{
 		preset->setScopeConfig(m_scopeWindow->serialize());
-	else preset->setScopeConfig(QByteArray());
+	}
+    else
+    {
+    	preset->setScopeConfig(QByteArray());
+    }
 
-	preset->clearChannels();
-	m_pluginManager->saveSettings(preset);
+    preset->clearChannels();
+    m_pluginManager->saveSettings(preset);
 
-	preset->setLayout(saveState());
+    preset->setLayout(saveState());
 }
 
 void MainWindow::createStatusBar()
diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp
index 2f01a254a..2f31c32e4 100644
--- a/sdrbase/plugin/pluginmanager.cpp
+++ b/sdrbase/plugin/pluginmanager.cpp
@@ -8,6 +8,10 @@
 #include "dsp/dspengine.h"
 #include "dsp/samplesource/samplesource.h"
 
+#include <iostream>
+#include <cstdio>
+#include "util/stacktrace.h"
+
 PluginManager::PluginManager(MainWindow* mainWindow, DSPEngine* dspEngine, QObject* parent) :
 	QObject(parent),
 	m_pluginAPI(this, mainWindow, dspEngine),
@@ -67,12 +71,18 @@ void PluginManager::removeChannelInstance(PluginGUI* pluginGUI)
 
 void PluginManager::registerSampleSource(const QString& sourceName, PluginInterface* plugin)
 {
+	std::cerr << "PluginManager::registerSampleSource "
+			<< plugin->getPluginDescriptor().displayedName.toStdString()
+			<< " with source name " << sourceName.toStdString() << std::endl;
+
 	m_sampleSourceRegistrations.append(SampleSourceRegistration(sourceName, plugin));
 }
 
 void PluginManager::loadSettings(const Preset* preset)
 {
-	qDebug("-------- [%s | %s] --------", qPrintable(preset->getGroup()), qPrintable(preset->getDescription()));
+	std::cerr << "PluginManager::loadSettings" << std::endl;
+
+	fprintf(stderr, "-------- [%s | %s] --------\n", qPrintable(preset->getGroup()), qPrintable(preset->getDescription()));
 
 	// copy currently open channels and clear list
 	ChannelInstanceRegistrations openChannels = m_channelInstanceRegistrations;
@@ -114,8 +124,10 @@ void PluginManager::loadSettings(const Preset* preset)
 	renameChannelInstances();
 
 	if(m_sampleSourceInstance != NULL) {
+		std::cerr << "m_sampleSourceInstance->deserializeGeneral (" << m_sampleSourceInstance->getName().toStdString() << ")" << std::endl;
 		m_sampleSourceInstance->deserializeGeneral(preset->getSourceGeneralConfig());
 		if(m_sampleSource == preset->getSource()) {
+			std::cerr << "m_sampleSourceInstance->deserialize" << std::endl;
 			m_sampleSourceInstance->deserialize(preset->getSourceConfig());
 		}
 	}
@@ -187,6 +199,8 @@ void PluginManager::fillSampleSourceSelector(QComboBox* comboBox)
 
 int PluginManager::selectSampleSource(int index)
 {
+	std::cout << "PluginManager::selectSampleSource by index" << std::endl;
+
 	m_dspEngine->stopAcquistion();
 
 	if(m_sampleSourceInstance != NULL) {
@@ -215,12 +229,15 @@ int PluginManager::selectSampleSource(int index)
 		return -1;
 
 	m_sampleSource = m_sampleSourceDevices[index].m_sourceName;
+	std::cerr << "m_sampleSource at index " << index << " is " << m_sampleSource.toStdString() << std::endl;
 	m_sampleSourceInstance = m_sampleSourceDevices[index].m_plugin->createSampleSource(m_sampleSource, m_sampleSourceDevices[index].m_address);
 	return index;
 }
 
 int PluginManager::selectSampleSource(const QString& source)
 {
+	std::cout << "PluginManager::selectSampleSource by name: " << source.toStdString() << std::endl;
+
 	int index = -1;
 
 	m_dspEngine->stopAcquistion();
@@ -249,6 +266,7 @@ int PluginManager::selectSampleSource(const QString& source)
 		return -1;
 
 	m_sampleSource = m_sampleSourceDevices[index].m_sourceName;
+	std::cerr << "m_sampleSource at index " << index << " is " << m_sampleSource.toStdString() << std::endl;
 	m_sampleSourceInstance = m_sampleSourceDevices[index].m_plugin->createSampleSource(m_sampleSource, m_sampleSourceDevices[index].m_address);
 	return index;
 }
diff --git a/sdrbase/settings/preset.cpp b/sdrbase/settings/preset.cpp
index 8af9dc972..85f5480dc 100644
--- a/sdrbase/settings/preset.cpp
+++ b/sdrbase/settings/preset.cpp
@@ -1,6 +1,8 @@
 #include "util/simpleserializer.h"
 #include "settings/preset.h"
 
+#include <iostream>
+
 Preset::Preset()
 {
 	resetToDefaults();
@@ -25,6 +27,8 @@ void Preset::resetToDefaults()
 
 QByteArray Preset::serialize() const
 {
+	std::cerr << "Preset::serialize (" << this->getSource().toStdString()<< ")" << std::endl;
+
 	SimpleSerializer s(1);
 	s.writeString(1, m_group);
 	s.writeString(2, m_description);
@@ -39,10 +43,13 @@ QByteArray Preset::serialize() const
 	s.writeBlob(11, m_sourceGeneralConfig);
 	s.writeBlob(12, m_sourceConfig);
 
-	s.writeS32(100, m_channelConfigs.size());
+	s.writeS32(200, m_channelConfigs.size());
+
+	std::cerr << "  m_group: " << m_group.toStdString() << std::endl;
+
 	for(int i = 0; i < m_channelConfigs.size(); i++) {
-		s.writeString(101 + i * 2, m_channelConfigs[i].m_channel);
-		s.writeBlob(102 + i * 2, m_channelConfigs[i].m_config);
+		s.writeString(201 + i * 2, m_channelConfigs[i].m_channel);
+		s.writeBlob(202 + i * 2, m_channelConfigs[i].m_config);
 	}
 
 	return s.final();
@@ -50,6 +57,7 @@ QByteArray Preset::serialize() const
 
 bool Preset::deserialize(const QByteArray& data)
 {
+	std::cerr << "Preset::deserialize (" << this->getSource().toStdString() << ")" << std::endl;
 	SimpleDeserializer d(data);
 
 	if(!d.isValid()) {
@@ -71,13 +79,16 @@ bool Preset::deserialize(const QByteArray& data)
 		d.readBlob(11, &m_sourceGeneralConfig);
 		d.readBlob(12, &m_sourceConfig);
 
+		std::cerr << "  m_group: " << m_group.toStdString() << std::endl;
+
 		qint32 channelCount = 0;
-		d.readS32(100, &channelCount, 0);
+		d.readS32(200, &channelCount, 0);
+
 		for(int i = 0; i < channelCount; i++) {
 			QString channel;
 			QByteArray config;
-			d.readString(101 + i * 2, &channel, "unknown-channel");
-			d.readBlob(102 + i * 2, &config);
+			d.readString(201 + i * 2, &channel, "unknown-channel");
+			d.readBlob(202 + i * 2, &config);
 			m_channelConfigs.append(ChannelConfig(channel, config));
 		}
 		return true;