diff --git a/devices/bladerf/devicebladerf.cpp b/devices/bladerf/devicebladerf.cpp
index a0b4e8937..0494efb63 100644
--- a/devices/bladerf/devicebladerf.cpp
+++ b/devices/bladerf/devicebladerf.cpp
@@ -85,4 +85,69 @@ struct bladerf *DeviceBladeRF::open_bladerf_from_serial(const char *serial)
}
}
+unsigned int BladerfSampleRates::m_rates[] = {1536, 1600, 2000, 2304, 2400, 3072, 3200, 4608, 4800, 6144, 7680, 9216, 9600, 10752, 12288, 18432, 19200, 24576, 30720, 36864, 39936};
+unsigned int BladerfSampleRates::m_nb_rates = 21;
+
+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 BladerfSampleRates::getNbRates()
+{
+ return BladerfSampleRates::m_nb_rates;
+}
+
+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/2000 == m_halfbw[i])
+ {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+unsigned int BladerfBandwidths::getNbBandwidths()
+{
+ return BladerfBandwidths::m_nb_halfbw;
+}
diff --git a/devices/bladerf/devicebladerf.h b/devices/bladerf/devicebladerf.h
index 2b8340bd1..b2efc9aaf 100644
--- a/devices/bladerf/devicebladerf.h
+++ b/devices/bladerf/devicebladerf.h
@@ -28,6 +28,24 @@ private:
static struct bladerf *open_bladerf_from_serial(const char *serial);
};
+class BladerfSampleRates {
+public:
+ static unsigned int getRate(unsigned int rate_index);
+ static unsigned int getRateIndex(unsigned int rate);
+ static unsigned int getNbRates();
+private:
+ static unsigned int m_rates[21];
+ static unsigned int m_nb_rates;
+};
+class BladerfBandwidths {
+public:
+ static unsigned int getBandwidth(unsigned int bandwidth_index);
+ static unsigned int getBandwidthIndex(unsigned int bandwidth);
+ static unsigned int getNbBandwidths();
+private:
+ static unsigned int m_halfbw[16];
+ static unsigned int m_nb_halfbw;
+};
#endif /* DEVICES_BLADERF_DEVICESDBLADERF_H_ */
diff --git a/plugins/samplesink/CMakeLists.txt b/plugins/samplesink/CMakeLists.txt
index 83a205b90..5d5c860f3 100644
--- a/plugins/samplesink/CMakeLists.txt
+++ b/plugins/samplesink/CMakeLists.txt
@@ -3,13 +3,13 @@ project(samplesink)
find_package(LibUSB)
find_package(LibBLADERF)
-#if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
-# add_subdirectory(bladerfoutput)
-#endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
+if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
+ add_subdirectory(bladerfoutput)
+endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
-#if (BUILD_DEBIAN)
-# add_subdirectory(bladerfoutput)
-#endif (BUILD_DEBIAN)
+if (BUILD_DEBIAN)
+ add_subdirectory(bladerfoutput)
+endif (BUILD_DEBIAN)
add_subdirectory(filesink)
diff --git a/plugins/samplesink/bladerfoutput/CMakeLists.txt b/plugins/samplesink/bladerfoutput/CMakeLists.txt
new file mode 100644
index 000000000..8ec0cf45a
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/CMakeLists.txt
@@ -0,0 +1,72 @@
+project(bladerfoutput)
+
+set(bladerfoutput_SOURCES
+ bladerfoutputgui.cpp
+ bladerfoutput.cpp
+ bladerfoutputplugin.cpp
+ bladerfoutputsettings.cpp
+ bladerfoutputthread.cpp
+)
+
+set(bladerfoutput_HEADERS
+ bladerfoutputgui.h
+ bladerfoutput.h
+ bladerfoutputplugin.h
+ bladerfoutputsettings.h
+ bladerfoutputthread.h
+)
+
+set(bladerfoutput_FORMS
+ bladerfoutputgui.ui
+)
+
+if (BUILD_DEBIAN)
+include_directories(
+ .
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/devices
+ ${LIBBLADERFLIBSRC}/include
+ ${LIBBLADERFLIBSRC}/src
+)
+else (BUILD_DEBIAN)
+include_directories(
+ .
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/devices
+ ${LIBBLADERF_INCLUDE_DIR}
+)
+endif (BUILD_DEBIAN)
+
+#include(${QT_USE_FILE})
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+
+#qt4_wrap_cpp(bladerfoutput_HEADERS_MOC ${bladerfoutput_HEADERS})
+qt5_wrap_ui(bladerfoutput_FORMS_HEADERS ${bladerfoutput_FORMS})
+
+add_library(outputbladerf SHARED
+ ${bladerfoutput_SOURCES}
+ ${bladerfoutput_HEADERS_MOC}
+ ${bladerfoutput_FORMS_HEADERS}
+)
+
+if (BUILD_DEBIAN)
+target_link_libraries(outputbladerf
+ ${QT_LIBRARIES}
+ bladerf
+ sdrbase
+ bladerfdevice
+)
+else (BUILD_DEBIAN)
+target_link_libraries(outputbladerf
+ ${QT_LIBRARIES}
+ ${LIBBLADERF_LIBRARIES}
+ sdrbase
+ bladerfdevice
+)
+endif (BUILD_DEBIAN)
+
+qt5_use_modules(outputbladerf Core Widgets)
+
+install(TARGETS outputbladerf DESTINATION lib/plugins/samplesink)
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutput.cpp b/plugins/samplesink/bladerfoutput/bladerfoutput.cpp
new file mode 100644
index 000000000..2f2f78ff7
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutput.cpp
@@ -0,0 +1,445 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+
+#include "util/simpleserializer.h"
+#include "dsp/dspcommands.h"
+#include "dsp/dspengine.h"
+#include "device/devicesinkapi.h"
+#include "device/devicesourceapi.h"
+
+#include "bladerfoutput.h"
+#include "bladerfoutputgui.h"
+#include "bladerfoutputthread.h"
+
+MESSAGE_CLASS_DEFINITION(BladerfOutput::MsgConfigureBladerf, Message)
+MESSAGE_CLASS_DEFINITION(BladerfOutput::MsgReportBladerf, Message)
+
+BladerfOutput::BladerfOutput(DeviceSinkAPI *deviceAPI) :
+ m_deviceAPI(deviceAPI),
+ m_settings(),
+ m_dev(0),
+ m_bladerfThread(0),
+ m_deviceDescription("BladeRFOutput")
+{
+ m_deviceAPI->setBuddySharedPtr(&m_sharedParams);
+}
+
+BladerfOutput::~BladerfOutput()
+{
+ stop();
+ m_deviceAPI->setBuddySharedPtr(0);
+}
+
+bool BladerfOutput::init(const Message& cmd)
+{
+ return false;
+}
+
+bool BladerfOutput::start(int device)
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ if (m_dev != 0)
+ {
+ stop();
+ }
+
+ int res;
+
+ m_sampleSourceFifo.resize(m_settings.m_devSampleRate); // 1s long
+
+ if (m_deviceAPI->getSourceBuddies().size() > 0)
+ {
+ DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];
+ DeviceBladeRFParams *buddySharedParams = (DeviceBladeRFParams *) buddy->getBuddySharedPtr();
+
+ if (buddySharedParams == 0)
+ {
+ qCritical("BladerfOutput::start: could not get shared parameters from buddy");
+ return false;
+ }
+
+ if (buddy->getDeviceSourceEngine()->state() == DSPDeviceSourceEngine::StRunning) // Rx side is running so it must have device ownership
+ {
+ if ((m_dev = buddySharedParams->m_dev) == 0) // get device handle from Rx but do not take ownership
+ {
+ qCritical("BladerfOutput::start: could not get BladeRF handle from buddy");
+ return false;
+ }
+ }
+ else // Rx is not running so Tx opens device and takes ownership
+ {
+ if (!DeviceBladeRF::open_bladerf(&m_dev, 0)) // TODO: fix; Open first available device as there is no proper handling for multiple devices
+ {
+ qCritical("BladerfOutput::start: could not open BladeRF");
+ return false;
+ }
+
+ m_sharedParams.m_dev = m_dev;
+ }
+ }
+ else // No Rx part open so Tx opens device and takes ownership
+ {
+ if (!DeviceBladeRF::open_bladerf(&m_dev, 0)) // TODO: fix; Open first available device as there is no proper handling for multiple devices
+ {
+ qCritical("BladerfOutput::start: could not open BladeRF");
+ return false;
+ }
+
+ m_sharedParams.m_dev = m_dev;
+ }
+
+ // TODO: adjust USB transfer data according to sample rate
+ if ((res = bladerf_sync_config(m_dev, BLADERF_MODULE_TX, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000)) < 0)
+ {
+ qCritical("BladerfOutput::start: bladerf_sync_config with return code %d", res);
+ goto failed;
+ }
+
+ if ((res = bladerf_enable_module(m_dev, BLADERF_MODULE_TX, true)) < 0)
+ {
+ qCritical("BladerfOutput::start: bladerf_enable_module with return code %d", res);
+ goto failed;
+ }
+
+ if((m_bladerfThread = new BladerfOutputThread(m_dev, &m_sampleSourceFifo)) == 0)
+ {
+ qFatal("BladerfOutput::start: out of memory");
+ goto failed;
+ }
+
+ m_bladerfThread->startWork();
+
+ mutexLocker.unlock();
+ applySettings(m_settings, true);
+
+ qDebug("BladerfOutput::start: started");
+
+ return true;
+
+failed:
+ stop();
+ return false;
+}
+
+void BladerfOutput::stop()
+{
+ QMutexLocker mutexLocker(&m_mutex);
+
+ if(m_bladerfThread != 0)
+ {
+ m_bladerfThread->stopWork();
+ delete m_bladerfThread;
+ m_bladerfThread = 0;
+ }
+
+ if (m_deviceAPI->getSourceBuddies().size() > 0)
+ {
+ DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];
+ DeviceBladeRFParams *buddySharedParams = (DeviceBladeRFParams *) buddy->getBuddySharedPtr();
+
+ if (buddy->getDeviceSourceEngine()->state() == DSPDeviceSourceEngine::StRunning) // Rx side running
+ {
+ if ((m_sharedParams.m_dev != 0) && (buddySharedParams->m_dev == 0)) // Tx has the ownership but not the Rx
+ {
+ buddySharedParams->m_dev = m_dev; // transfer ownership
+ }
+ }
+ else // Rx is not running so Tx must have the ownership
+ {
+ if(m_dev != 0) // close BladeRF
+ {
+ bladerf_close(m_dev);
+ m_dev = 0;
+ }
+ }
+ }
+ else // No Rx part open
+ {
+ if(m_dev != 0) // close BladeRF
+ {
+ bladerf_close(m_dev);
+ m_dev = 0;
+ }
+ }
+
+ m_sharedParams.m_dev = 0;
+}
+
+const QString& BladerfOutput::getDeviceDescription() const
+{
+ return m_deviceDescription;
+}
+
+int BladerfOutput::getSampleRate() const
+{
+ int rate = m_settings.m_devSampleRate;
+ return (rate / (1<getSourceBuddies().size() > 0)
+ {
+ DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0];
+ DeviceBladeRFParams *buddySharedParams = (DeviceBladeRFParams *) buddy->getBuddySharedPtr();
+
+ if (buddy->getDeviceSourceEngine()->state() == DSPDeviceSourceEngine::StRunning) // Tx side running
+ {
+ changeSettings = false;
+ }
+ else
+ {
+ changeSettings = true;
+ }
+ }
+ else // No Rx open
+ {
+ changeSettings = true;
+ }
+
+ if (changeSettings)
+ {
+ if (m_settings.m_xb200)
+ {
+ if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0)
+ {
+ qDebug("BladerfOutput::applySettings: bladerf_expansion_attach(xb200) failed");
+ }
+ else
+ {
+ qDebug() << "BladerfOutput::applySettings: Attach XB200";
+ }
+ }
+ else
+ {
+ if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0)
+ {
+ qDebug("BladerfOutput::applySettings: bladerf_expansion_attach(none) failed");
+ }
+ else
+ {
+ qDebug() << "BladerfOutput::applySettings: Detach XB200";
+ }
+ }
+
+ m_sharedParams.m_xb200Attached = m_settings.m_xb200;
+ }
+ }
+ }
+
+ if ((m_settings.m_xb200Path != settings.m_xb200Path) || force)
+ {
+ m_settings.m_xb200Path = settings.m_xb200Path;
+
+ if (m_dev != 0)
+ {
+ if(bladerf_xb200_set_path(m_dev, BLADERF_MODULE_TX, m_settings.m_xb200Path) != 0)
+ {
+ qDebug("BladerfOutput::applySettings: bladerf_xb200_set_path(BLADERF_MODULE_TX) failed");
+ }
+ else
+ {
+ qDebug() << "BladerfOutput::applySettings: set xb200 path to " << m_settings.m_xb200Path;
+ }
+ }
+ }
+
+ if ((m_settings.m_xb200Filter != settings.m_xb200Filter) || force)
+ {
+ m_settings.m_xb200Filter = settings.m_xb200Filter;
+
+ if (m_dev != 0)
+ {
+ if(bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_TX, m_settings.m_xb200Filter) != 0)
+ {
+ qDebug("BladerfOutput::applySettings: bladerf_xb200_set_filterbank(BLADERF_MODULE_TX) failed");
+ }
+ else
+ {
+ qDebug() << "BladerfOutput::applySettings: set xb200 filter to " << m_settings.m_xb200Filter;
+ }
+ }
+ }
+
+ if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
+ {
+ m_settings.m_devSampleRate = settings.m_devSampleRate;
+ forwardChange = true;
+
+ if (m_dev != 0)
+ {
+ unsigned int actualSamplerate;
+
+ if (bladerf_set_sample_rate(m_dev, BLADERF_MODULE_TX, m_settings.m_devSampleRate, &actualSamplerate) < 0)
+ {
+ qCritical("BladerfOutput::applySettings: could not set sample rate: %d", m_settings.m_devSampleRate);
+ }
+ else
+ {
+ qDebug() << "BladerfOutput::applySettings: bladerf_set_sample_rate(BLADERF_MODULE_TX) actual sample rate is " << actualSamplerate;
+ }
+ }
+ }
+
+ if ((m_settings.m_bandwidth != settings.m_bandwidth) || force)
+ {
+ m_settings.m_bandwidth = settings.m_bandwidth;
+
+ if(m_dev != 0)
+ {
+ unsigned int actualBandwidth;
+
+ if( bladerf_set_bandwidth(m_dev, BLADERF_MODULE_TX, m_settings.m_bandwidth, &actualBandwidth) < 0)
+ {
+ qCritical("BladerfOutput::applySettings: could not set bandwidth: %d", m_settings.m_bandwidth);
+ }
+ else
+ {
+ qDebug() << "BladerfOutput::applySettings: bladerf_set_bandwidth(BLADERF_MODULE_TX) actual bandwidth is " << actualBandwidth;
+ }
+ }
+ }
+
+ if ((m_settings.m_log2Interp != settings.m_log2Interp) || force)
+ {
+ m_settings.m_log2Interp = settings.m_log2Interp;
+ forwardChange = true;
+
+ if(m_dev != 0)
+ {
+ m_bladerfThread->setLog2Interpolation(m_settings.m_log2Interp);
+ qDebug() << "BladerfOutput::applySettings: set interpolation to " << (1<getDeviceInputMessageQueue()->push(notif);
+ }
+
+ qDebug() << "BladerfOutput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
+ << " device center freq: " << deviceCenterFrequency << " Hz"
+ << " device sample rate: " << m_settings.m_devSampleRate << "Hz"
+ << " baseband sample rate: " << m_settings.m_devSampleRate/(1<. //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_BLADERFOUTPUT_H
+#define INCLUDE_BLADERFOUTPUT_H
+
+#include
+#include "bladerf/devicebladerf.h"
+#include "bladerf/devicebladerfparam.h"
+
+#include
+#include
+
+#include "bladerfoutputsettings.h"
+
+class DeviceSinkAPI;
+class BladerfOutputThread;
+
+class BladerfOutput : public DeviceSampleSink {
+public:
+ class MsgConfigureBladerf : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const BladeRFOutputSettings& getSettings() const { return m_settings; }
+
+ static MsgConfigureBladerf* create(const BladeRFOutputSettings& settings)
+ {
+ return new MsgConfigureBladerf(settings);
+ }
+
+ private:
+ BladeRFOutputSettings m_settings;
+
+ MsgConfigureBladerf(const BladeRFOutputSettings& settings) :
+ Message(),
+ m_settings(settings)
+ { }
+ };
+
+ class MsgReportBladerf : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+
+ static MsgReportBladerf* create()
+ {
+ return new MsgReportBladerf();
+ }
+
+ protected:
+
+ MsgReportBladerf() :
+ Message()
+ { }
+ };
+
+ BladerfOutput(DeviceSinkAPI *deviceAPI);
+ virtual ~BladerfOutput();
+
+ virtual bool init(const Message& message);
+ virtual bool start(int device);
+ virtual void stop();
+
+ virtual const QString& getDeviceDescription() const;
+ virtual int getSampleRate() const;
+ virtual quint64 getCenterFrequency() const;
+
+ virtual bool handleMessage(const Message& message);
+
+private:
+ bool applySettings(const BladeRFOutputSettings& settings, bool force);
+
+ DeviceSinkAPI *m_deviceAPI;
+ QMutex m_mutex;
+ BladeRFOutputSettings m_settings;
+ struct bladerf* m_dev;
+ BladerfOutputThread* m_bladerfThread;
+ QString m_deviceDescription;
+ DeviceBladeRFParams m_sharedParams;
+};
+
+#endif // INCLUDE_BLADERFOUTPUT_H
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutput.pro b/plugins/samplesink/bladerfoutput/bladerfoutput.pro
new file mode 100644
index 000000000..300b323ac
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutput.pro
@@ -0,0 +1,45 @@
+#--------------------------------------------
+#
+# Pro file for Windows builds with Qt Creator
+#
+#--------------------------------------------
+
+TEMPLATE = lib
+CONFIG += plugin
+
+QT += core gui widgets multimedia opengl
+
+TARGET = inputbladerf
+
+DEFINES += USE_SSE2=1
+QMAKE_CXXFLAGS += -msse2
+DEFINES += USE_SSE4_1=1
+QMAKE_CXXFLAGS += -msse4.1
+
+CONFIG(MINGW32):LIBBLADERFSRC = "D:\softs\bladeRF\host\libraries\libbladeRF\include"
+CONFIG(MINGW64):LIBBLADERFSRC = "D:\softs\bladeRF\host\libraries\libbladeRF\include"
+INCLUDEPATH += $$PWD
+INCLUDEPATH += ../../../sdrbase
+INCLUDEPATH += $$LIBBLADERFSRC
+
+CONFIG(Release):build_subdir = release
+CONFIG(Debug):build_subdir = debug
+
+SOURCES += bladerfoutputgui.cpp\
+ bladerfoutput.cpp\
+ bladerfoutputplugin.cpp\
+ bladerfoutputsettings.cpp\
+ bladerfoutputthread.cpp
+
+HEADERS += bladerfoutputgui.h\
+ bladerfoutput.h\
+ bladerfoutputplugin.h\
+ bladerfoutputsettings.h\
+ bladerfoutputthread.h
+
+FORMS += bladerfoutputgui.ui
+
+LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
+LIBS += -L../../../libbladerf/$${build_subdir} -llibbladerf
+
+RESOURCES = ../../../sdrbase/resources/res.qrc
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputgui.cpp b/plugins/samplesink/bladerfoutput/bladerfoutputgui.cpp
new file mode 100644
index 000000000..55d178f44
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputgui.cpp
@@ -0,0 +1,422 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+#include
+
+#include "ui_bladerfoutputgui.h"
+#include "gui/colormapper.h"
+#include "gui/glspectrum.h"
+#include "dsp/dspengine.h"
+#include "dsp/dspcommands.h"
+#include "device/devicesinkapi.h"
+#include "dsp/filerecord.h"
+#include "bladerfoutputgui.h"
+#include "bladerf/devicebladerfvalues.h"
+
+BladerfOutputGui::BladerfOutputGui(DeviceSinkAPI *deviceAPI, QWidget* parent) :
+ QWidget(parent),
+ ui(new Ui::BladerfOutputGui),
+ m_deviceAPI(deviceAPI),
+ m_settings(),
+ m_deviceSampleSink(NULL),
+ m_sampleRate(0),
+ m_lastEngineState((DSPDeviceSinkEngine::State)-1)
+{
+ ui->setupUi(this);
+ ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
+ ui->centerFrequency->setValueRange(7, BLADERF_FREQUENCY_MIN_XB200/1000, BLADERF_FREQUENCY_MAX/1000);
+
+ ui->samplerate->clear();
+ for (int i = 0; i < BladerfSampleRates::getNbRates(); i++)
+ {
+ ui->samplerate->addItem(QString::number(BladerfSampleRates::getRate(i)));
+ }
+
+ ui->bandwidth->clear();
+ for (int i = 0; i < BladerfBandwidths::getNbBandwidths(); i++)
+ {
+ ui->bandwidth->addItem(QString::number(BladerfBandwidths::getBandwidth(i)));
+ }
+
+ connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
+ connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
+ m_statusTimer.start(500);
+
+ displaySettings();
+
+ m_deviceSampleSink = new BladerfOutput(m_deviceAPI);
+ m_deviceAPI->setSink(m_deviceSampleSink);
+
+ char recFileNameCStr[30];
+ sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceAPI->getDeviceUID());
+ m_fileSink = new FileRecord(std::string(recFileNameCStr));
+// m_deviceAPI->addSink(m_fileSink);
+
+ connect(m_deviceAPI->getDeviceOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleDSPMessages()), Qt::QueuedConnection);
+}
+
+BladerfOutputGui::~BladerfOutputGui()
+{
+// m_deviceAPI->removeSink(m_fileSink);
+ delete m_fileSink;
+ delete m_deviceSampleSink; // Valgrind memcheck
+ delete ui;
+}
+
+void BladerfOutputGui::destroy()
+{
+ delete this;
+}
+
+void BladerfOutputGui::setName(const QString& name)
+{
+ setObjectName(name);
+}
+
+QString BladerfOutputGui::getName() const
+{
+ return objectName();
+}
+
+void BladerfOutputGui::resetToDefaults()
+{
+ m_settings.resetToDefaults();
+ displaySettings();
+ sendSettings();
+}
+
+qint64 BladerfOutputGui::getCenterFrequency() const
+{
+ return m_settings.m_centerFrequency;
+}
+
+void BladerfOutputGui::setCenterFrequency(qint64 centerFrequency)
+{
+ m_settings.m_centerFrequency = centerFrequency;
+ displaySettings();
+ sendSettings();
+}
+
+QByteArray BladerfOutputGui::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool BladerfOutputGui::deserialize(const QByteArray& data)
+{
+ if(m_settings.deserialize(data)) {
+ displaySettings();
+ sendSettings();
+ return true;
+ } else {
+ resetToDefaults();
+ return false;
+ }
+}
+
+bool BladerfOutputGui::handleMessage(const Message& message)
+{
+ if (BladerfOutput::MsgReportBladerf::match(message))
+ {
+ displaySettings();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void BladerfOutputGui::handleDSPMessages()
+{
+ Message* message;
+
+ while ((message = m_deviceAPI->getDeviceOutputMessageQueue()->pop()) != 0)
+ {
+ qDebug("BladerfOutputGui::handleDSPMessages: message: %s", message->getIdentifier());
+
+ if (DSPSignalNotification::match(*message))
+ {
+ DSPSignalNotification* notif = (DSPSignalNotification*) message;
+ m_sampleRate = notif->getSampleRate();
+ m_deviceCenterFrequency = notif->getCenterFrequency();
+ qDebug("BladerfOutputGui::handleDSPMessages: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency());
+ updateSampleRateAndFrequency();
+ m_fileSink->handleMessage(*notif); // forward to file sink
+
+ delete message;
+ }
+ }
+}
+
+void BladerfOutputGui::updateSampleRateAndFrequency()
+{
+ m_deviceAPI->getSpectrum()->setSampleRate(m_sampleRate);
+ m_deviceAPI->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency);
+ ui->deviceRateLabel->setText(tr("%1k").arg((float)m_sampleRate / 1000));
+}
+
+void BladerfOutputGui::displaySettings()
+{
+ ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
+
+ unsigned int sampleRateIndex = BladerfSampleRates::getRateIndex(m_settings.m_devSampleRate);
+ ui->samplerate->setCurrentIndex(sampleRateIndex);
+
+ unsigned int bandwidthIndex = BladerfBandwidths::getBandwidthIndex(m_settings.m_bandwidth);
+ ui->bandwidth->setCurrentIndex(bandwidthIndex);
+
+ ui->interp->setCurrentIndex(m_settings.m_log2Interp);
+
+ ui->vga1Text->setText(tr("%1dB").arg(m_settings.m_vga1));
+ ui->vga1->setValue(m_settings.m_vga1);
+
+ ui->vga2Text->setText(tr("%1dB").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 BladerfOutputGui::sendSettings()
+{
+ if(!m_updateTimer.isActive())
+ m_updateTimer.start(100);
+}
+
+void BladerfOutputGui::on_centerFrequency_changed(quint64 value)
+{
+ m_settings.m_centerFrequency = value * 1000;
+ sendSettings();
+}
+
+void BladerfOutputGui::on_samplerate_currentIndexChanged(int index)
+{
+ int newrate = BladerfSampleRates::getRate(index);
+ m_settings.m_devSampleRate = newrate * 1000;
+ sendSettings();
+}
+
+void BladerfOutputGui::on_bandwidth_currentIndexChanged(int index)
+{
+ int newbw = BladerfBandwidths::getBandwidth(index);
+ m_settings.m_bandwidth = newbw * 1000;
+ sendSettings();
+}
+
+void BladerfOutputGui::on_decim_currentIndexChanged(int index)
+{
+ if ((index <0) || (index > 5))
+ return;
+ m_settings.m_log2Interp = index;
+ sendSettings();
+}
+
+void BladerfOutputGui::on_vga1_valueChanged(int value)
+{
+ if ((value < BLADERF_RXVGA1_GAIN_MIN) || (value > BLADERF_RXVGA1_GAIN_MAX))
+ return;
+
+ ui->vga1Text->setText(tr("%1dB").arg(value));
+ m_settings.m_vga1 = value;
+ sendSettings();
+}
+
+void BladerfOutputGui::on_vga2_valueChanged(int value)
+{
+ if ((value < BLADERF_RXVGA2_GAIN_MIN) || (value > BLADERF_RXVGA2_GAIN_MAX))
+ return;
+
+ ui->vga2Text->setText(tr("%1dB").arg(value));
+ m_settings.m_vga2 = value;
+ sendSettings();
+}
+
+void BladerfOutputGui::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;
+ }
+
+ if (m_settings.m_xb200)
+ {
+ ui->centerFrequency->setValueRange(7, BLADERF_FREQUENCY_MIN_XB200/1000, BLADERF_FREQUENCY_MAX/1000);
+ }
+ else
+ {
+ ui->centerFrequency->setValueRange(7, BLADERF_FREQUENCY_MIN/1000, BLADERF_FREQUENCY_MAX/1000);
+ }
+
+ sendSettings();
+}
+
+void BladerfOutputGui::on_startStop_toggled(bool checked)
+{
+ if (checked)
+ {
+ if (m_deviceAPI->initGeneration())
+ {
+ m_deviceAPI->startGeneration();
+ DSPEngine::instance()->startAudioOutput();
+ }
+ }
+ else
+ {
+ m_deviceAPI->stopGeneration();
+ DSPEngine::instance()->stopAudioOutput();
+ }
+}
+
+void BladerfOutputGui::on_record_toggled(bool checked)
+{
+// if (checked)
+// {
+// ui->record->setStyleSheet("QToolButton { background-color : red; }");
+// m_fileSink->startRecording();
+// }
+// else
+// {
+// ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
+// m_fileSink->stopRecording();
+// }
+}
+
+void BladerfOutputGui::updateHardware()
+{
+ qDebug() << "BladerfGui::updateHardware";
+ BladerfOutput::MsgConfigureBladerf* message = BladerfOutput::MsgConfigureBladerf::create( m_settings);
+ m_deviceSampleSink->getInputMessageQueue()->push(message);
+ m_updateTimer.stop();
+}
+
+void BladerfOutputGui::updateStatus()
+{
+ int state = m_deviceAPI->state();
+
+ if(m_lastEngineState != state)
+ {
+ switch(state)
+ {
+ case DSPDeviceSinkEngine::StNotStarted:
+ ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
+ break;
+ case DSPDeviceSinkEngine::StIdle:
+ ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
+ break;
+ case DSPDeviceSinkEngine::StRunning:
+ ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
+ break;
+ case DSPDeviceSinkEngine::StError:
+ ui->startStop->setStyleSheet("QToolButton { background-color : magenta; }");
+ QMessageBox::information(this, tr("Message"), m_deviceAPI->errorMessage());
+ break;
+ default:
+ break;
+ }
+
+ m_lastEngineState = state;
+ }
+}
+
+unsigned int BladerfOutputGui::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;
+ }
+}
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputgui.h b/plugins/samplesink/bladerfoutput/bladerfoutputgui.h
new file mode 100644
index 000000000..a0db818c3
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputgui.h
@@ -0,0 +1,84 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_BLADERFOUTPUTGUI_H
+#define INCLUDE_BLADERFOUTPUTGUI_H
+
+#include
+#include "plugin/plugingui.h"
+
+#include "bladerfoutput.h"
+
+class DeviceSinkAPI;
+class DeviceSampleSink;
+class FileRecord;
+
+namespace Ui {
+ class BladerfOutputGui;
+}
+
+class BladerfOutputGui : public QWidget, public PluginGUI {
+ Q_OBJECT
+
+public:
+ explicit BladerfOutputGui(DeviceSinkAPI *deviceAPI, QWidget* parent = NULL);
+ virtual ~BladerfOutputGui();
+ void destroy();
+
+ void setName(const QString& name);
+ QString getName() const;
+
+ void resetToDefaults();
+ virtual qint64 getCenterFrequency() const;
+ virtual void setCenterFrequency(qint64 centerFrequency);
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+ virtual bool handleMessage(const Message& message);
+
+private:
+ Ui::BladerfOutputGui* ui;
+
+ DeviceSinkAPI* m_deviceAPI;
+ BladeRFOutputSettings m_settings;
+ QTimer m_updateTimer;
+ QTimer m_statusTimer;
+ DeviceSampleSink* m_deviceSampleSink;
+ FileRecord *m_fileSink; //!< File sink to record device I/Q output TODO: change to file input
+ int m_sampleRate;
+ quint64 m_deviceCenterFrequency; //!< Center frequency in device
+ int m_lastEngineState;
+
+ void displaySettings();
+ void sendSettings();
+ unsigned int getXb200Index(bool xb_200, bladerf_xb200_path xb200Path, bladerf_xb200_filter xb200Filter);
+ void updateSampleRateAndFrequency();
+
+private slots:
+ void handleDSPMessages();
+ void on_centerFrequency_changed(quint64 value);
+ void on_samplerate_currentIndexChanged(int index);
+ void on_bandwidth_currentIndexChanged(int index);
+ void on_decim_currentIndexChanged(int index);
+ void on_vga1_valueChanged(int value);
+ void on_vga2_valueChanged(int value);
+ void on_xb200_currentIndexChanged(int index);
+ void on_startStop_toggled(bool checked);
+ void on_record_toggled(bool checked);
+ void updateHardware();
+ void updateStatus();
+};
+
+#endif // INCLUDE_BLADERFOUTPUTGUI_H
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputgui.ui b/plugins/samplesink/bladerfoutput/bladerfoutputgui.ui
new file mode 100644
index 000000000..06feb7dcd
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputgui.ui
@@ -0,0 +1,571 @@
+
+
+ BladerfOutputGui
+
+
+
+ 0
+ 0
+ 259
+ 251
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 210
+
+
+
+
+ Sans Serif
+ 9
+
+
+
+ BladeRF
+
+
+
+ 3
+
+
+ 2
+
+ -
+
+
-
+
+
-
+
+
-
+
+
+ start/stop acquisition
+
+
+
+
+
+
+ :/play.png
+ :/stop.png:/play.png
+
+
+
+ -
+
+
+ Toggle record I/Q samples from device
+
+
+
+
+
+
+ :/record_off.png
+ :/record_on.png:/record_off.png
+
+
+
+
+
+ -
+
+
-
+
+
+ I/Q sample rate kS/s
+
+
+ 00000k
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ Monospace
+ 20
+
+
+
+ SizeVerCursor
+
+
+ Qt::StrongFocus
+
+
+ Tuner center frequency in kHz
+
+
+
+ -
+
+
+ kHz
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ xb200
+
+
+
+ -
+
+
+ XB200 board mode
+
+
+ None
+
+
+ 0
+
+
+ 5
+
+
-
+
+ None
+
+
+ -
+
+ Bypass
+
+
+ -
+
+ Auto 1dB
+
+
+ -
+
+ Auto 3dB
+
+
+ -
+
+ Custom
+
+
+ -
+
+ 50M
+
+
+ -
+
+ 144M
+
+
+ -
+
+ 222M
+
+
+
+
+ -
+
+
+ Int
+
+
+
+ -
+
+
+
+ 50
+ 16777215
+
+
+
+ Interpolation factor
+
+
+ 3
+
+
-
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 4
+
+
+ -
+
+ 8
+
+
+ -
+
+ 16
+
+
+ -
+
+ 32
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 3
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ SR
+
+
+
+ -
+
+
+
+ 70
+ 16777215
+
+
+
+ Sample rate in kS/s
+
+
+
+ -
+
+
+ kS/s
+
+
+
+ -
+
+
+
+ 70
+ 16777215
+
+
+
+ IF bandwidth in kHz
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ BW
+
+
+
+ -
+
+
+ kHz
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 3
+
+
-
+
+
+ Amplifier before filtering gain (dB)
+
+
+ 5
+
+
+ 30
+
+
+ 1
+
+
+ 20
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 40
+ 0
+
+
+
+ 20
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ VGA1
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ 3
+
+
-
+
+
+ VGA2
+
+
+
+ -
+
+
+ Amplifier before ADC gain (dB)
+
+
+ 30
+
+
+ 3
+
+
+ 3
+
+
+ 9
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+ 40
+ 0
+
+
+
+ 9
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+ ValueDial
+ QWidget
+
+ 1
+
+
+ ButtonSwitch
+ QToolButton
+
+
+
+
+
+
+
+
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp
new file mode 100644
index 000000000..42fbf23b3
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp
@@ -0,0 +1,92 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include "plugin/pluginapi.h"
+#include "util/simpleserializer.h"
+#include
+
+#include "bladerfoutputplugin.h"
+#include "bladerfoutputgui.h"
+
+const PluginDescriptor BladerfOutputPlugin::m_pluginDescriptor = {
+ QString("BladerRF Output"),
+ QString("3.0.0"),
+ QString("(c) Edouard Griffiths, F4EXB"),
+ QString("https://github.com/f4exb/sdrangel"),
+ true,
+ QString("https://github.com/f4exb/sdrangel")
+};
+
+const QString BladerfOutputPlugin::m_hardwareID = "BladeRF";
+const QString BladerfOutputPlugin::m_deviceTypeID = BLADERFOUTPUT_DEVICE_TYPE_ID;
+
+BladerfOutputPlugin::BladerfOutputPlugin(QObject* parent) :
+ QObject(parent)
+{
+}
+
+const PluginDescriptor& BladerfOutputPlugin::getPluginDescriptor() const
+{
+ return m_pluginDescriptor;
+}
+
+void BladerfOutputPlugin::initPlugin(PluginAPI* pluginAPI)
+{
+ pluginAPI->registerSampleSource(m_deviceTypeID, this);
+}
+
+PluginInterface::SamplingDevices BladerfOutputPlugin::enumSampleSinks()
+{
+ SamplingDevices result;
+ struct bladerf_devinfo *devinfo = 0;
+
+ int count = bladerf_get_device_list(&devinfo);
+
+ for(int i = 0; i < count; i++)
+ {
+ QString displayedName(QString("BladeRF[%1] %2").arg(devinfo[i].instance).arg(devinfo[i].serial));
+
+ result.append(SamplingDevice(displayedName,
+ m_hardwareID,
+ m_deviceTypeID,
+ QString(devinfo[i].serial),
+ i));
+ }
+
+ if (devinfo)
+ {
+ bladerf_free_device_list(devinfo); // Valgrind memcheck
+ }
+
+ return result;
+}
+
+PluginGUI* BladerfOutputPlugin::createSampleSinkPluginGUI(const QString& sinkId,QWidget **widget, DeviceSinkAPI *deviceAPI)
+{
+ if(sinkId == m_deviceTypeID)
+ {
+ BladerfOutputGui* gui = new BladerfOutputGui(deviceAPI);
+ *widget = gui;
+ return gui;
+ }
+ else
+ {
+ return 0;
+ }
+}
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h
new file mode 100644
index 000000000..9337354f2
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_BLADERFOUTPUTPLUGIN_H
+#define INCLUDE_BLADERFOUTPUTPLUGIN_H
+
+#include
+#include "plugin/plugininterface.h"
+
+class PluginAPI;
+
+#define BLADERFOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesource.bladerfoutput"
+
+class BladerfOutputPlugin : public QObject, public PluginInterface {
+ Q_OBJECT
+ Q_INTERFACES(PluginInterface)
+ Q_PLUGIN_METADATA(IID BLADERFOUTPUT_DEVICE_TYPE_ID)
+
+public:
+ explicit BladerfOutputPlugin(QObject* parent = NULL);
+
+ const PluginDescriptor& getPluginDescriptor() const;
+ void initPlugin(PluginAPI* pluginAPI);
+
+ virtual SamplingDevices enumSampleSinks();
+ virtual PluginGUI* createSampleSinkPluginGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI);
+
+ static const QString m_hardwareID;
+ static const QString m_deviceTypeID;
+
+private:
+ static const PluginDescriptor m_pluginDescriptor;
+};
+
+#endif // INCLUDE_BLADERFOUTPUTPLUGIN_H
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputsettings.cpp b/plugins/samplesink/bladerfoutput/bladerfoutputsettings.cpp
new file mode 100644
index 000000000..e106e0658
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputsettings.cpp
@@ -0,0 +1,88 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include "util/simpleserializer.h"
+#include "bladerfoutputsettings.h"
+
+
+BladeRFOutputSettings::BladeRFOutputSettings()
+{
+ resetToDefaults();
+}
+
+void BladeRFOutputSettings::resetToDefaults()
+{
+ m_centerFrequency = 435000*1000;
+ m_devSampleRate = 3072000;
+ m_vga1 = 20;
+ m_vga2 = 9;
+ m_bandwidth = 1500000;
+ m_log2Interp = 0;
+ m_xb200 = false;
+ m_xb200Path = BLADERF_XB200_MIX;
+ m_xb200Filter = BLADERF_XB200_AUTO_1DB;
+}
+
+QByteArray BladeRFOutputSettings::serialize() const
+{
+ SimpleSerializer s(1);
+
+ s.writeS32(1, m_devSampleRate);
+ s.writeS32(2, m_vga1);
+ s.writeS32(3, m_vga2);
+ s.writeS32(4, m_bandwidth);
+ s.writeU32(5, m_log2Interp);
+ s.writeBool(6, m_xb200);
+ s.writeS32(7, (int) m_xb200Path);
+ s.writeS32(8, (int) m_xb200Filter);
+
+ return s.final();
+}
+
+bool BladeRFOutputSettings::deserialize(const QByteArray& data)
+{
+ SimpleDeserializer d(data);
+
+ if (!d.isValid())
+ {
+ resetToDefaults();
+ return false;
+ }
+
+ if (d.getVersion() == 1)
+ {
+ int intval;
+
+ d.readS32(1, &m_devSampleRate);
+ d.readS32(2, &m_vga1);
+ d.readS32(3, &m_vga2);
+ d.readS32(4, &m_bandwidth);
+ d.readU32(5, &m_log2Interp);
+ 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;
+ }
+}
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputsettings.h b/plugins/samplesink/bladerfoutput/bladerfoutputsettings.h
new file mode 100644
index 000000000..ca51895e6
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputsettings.h
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _BLADERF_BLADERFOUTPUTSETTINGS_H_
+#define _BLADERF_BLADERFOUTPUTSETTINGS_H_
+
+#include
+#include
+
+struct BladeRFOutputSettings {
+ quint64 m_centerFrequency;
+ qint32 m_devSampleRate;
+ qint32 m_vga1;
+ qint32 m_vga2;
+ qint32 m_bandwidth;
+ quint32 m_log2Interp;
+ bool m_xb200;
+ bladerf_xb200_path m_xb200Path;
+ bladerf_xb200_filter m_xb200Filter;
+
+ BladeRFOutputSettings();
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+};
+
+#endif /* _BLADERF_BLADERFOUTPUTSETTINGS_H_ */
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputthread.cpp b/plugins/samplesink/bladerfoutput/bladerfoutputthread.cpp
new file mode 100644
index 000000000..d006f8825
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputthread.cpp
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include "bladerfoutputthread.h"
+
+
+
+BladerfOutputThread::BladerfOutputThread(struct bladerf* dev, SampleSourceFifo* sampleFifo, QObject* parent) :
+ QThread(parent),
+ m_running(false),
+ m_dev(dev),
+ m_sampleFifo(sampleFifo),
+ m_log2Interp(0),
+ m_fcPos(0)
+{
+ m_sampleFifo->resize(BLADERFOUTPUT_BLOCKSIZE);
+}
+
+BladerfOutputThread::~BladerfOutputThread()
+{
+ stopWork();
+}
+
+void BladerfOutputThread::startWork()
+{
+ m_startWaitMutex.lock();
+ start();
+ while(!m_running)
+ m_startWaiter.wait(&m_startWaitMutex, 100);
+ m_startWaitMutex.unlock();
+}
+
+void BladerfOutputThread::stopWork()
+{
+ m_running = false;
+ wait();
+}
+
+void BladerfOutputThread::setLog2Interpolation(unsigned int log2_interp)
+{
+ m_log2Interp = log2_interp;
+}
+
+void BladerfOutputThread::run()
+{
+ int res;
+
+ m_running = true;
+ m_startWaiter.wakeAll();
+
+ while (m_running)
+ {
+ callback(m_buf, BLADERFOUTPUT_BLOCKSIZE);
+
+ if((res = bladerf_sync_tx(m_dev, m_buf, BLADERFOUTPUT_BLOCKSIZE, NULL, 10000)) < 0)
+ {
+ qCritical("BladerdOutputThread:run: sync error: %s", strerror(errno));
+ break;
+ }
+ }
+
+ m_running = false;
+}
+
+// Interpolate according to specified log2 (ex: log2=4 => decim=16)
+void BladerfOutputThread::callback(qint16* buf, qint32 len)
+{
+ SampleVector::iterator beginRead;
+ m_sampleFifo->readAdvance(beginRead, len);
+ beginRead -= len;
+
+ if (m_log2Interp == 0)
+ {
+ m_interpolators.interpolate1(&beginRead, buf, len);
+ }
+ else
+ {
+ switch (m_log2Interp)
+ {
+ case 1:
+ m_interpolators.interpolate2_cen(&beginRead, buf, len);
+ break;
+ case 2:
+ m_interpolators.interpolate4_cen(&beginRead, buf, len);
+ break;
+ case 3:
+ m_interpolators.interpolate8_cen(&beginRead, buf, len);
+ break;
+ case 4:
+ m_interpolators.interpolate16_cen(&beginRead, buf, len);
+ break;
+ case 5:
+ m_interpolators.interpolate32_cen(&beginRead, buf, len);
+ break;
+ case 6:
+ m_interpolators.interpolate64_cen(&beginRead, buf, len);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputthread.h b/plugins/samplesink/bladerfoutput/bladerfoutputthread.h
new file mode 100644
index 000000000..256363f5a
--- /dev/null
+++ b/plugins/samplesink/bladerfoutput/bladerfoutputthread.h
@@ -0,0 +1,59 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// 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 . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDE_BLADERFOUTPUTTHREAD_H
+#define INCLUDE_BLADERFOUTPUTTHREAD_H
+
+#include
+#include
+#include
+#include
+#include "dsp/samplesourcefifo.h"
+#include "dsp/interpolators.h"
+
+#define BLADERFOUTPUT_BLOCKSIZE (1<<14)
+
+class BladerfOutputThread : public QThread {
+ Q_OBJECT
+
+public:
+ BladerfOutputThread(struct bladerf* dev, SampleSourceFifo* sampleFifo, QObject* parent = NULL);
+ ~BladerfOutputThread();
+
+ void startWork();
+ void stopWork();
+ void setLog2Interpolation(unsigned int log2_interp);
+ void setFcPos(int fcPos);
+
+private:
+ QMutex m_startWaitMutex;
+ QWaitCondition m_startWaiter;
+ bool m_running;
+
+ struct bladerf* m_dev;
+ qint16 m_buf[2*BLADERFOUTPUT_BLOCKSIZE];
+ SampleSourceFifo* m_sampleFifo;
+
+ unsigned int m_log2Interp;
+ int m_fcPos;
+
+ Interpolators m_interpolators;
+
+ void run();
+ void callback(qint16* buf, qint32 len);
+};
+
+#endif // INCLUDE_BLADERFOUTPUTTHREAD_H
diff --git a/plugins/samplesink/filesink/filesinkgui.h b/plugins/samplesink/filesink/filesinkgui.h
index ad7ea8ce1..259ab5f27 100644
--- a/plugins/samplesink/filesink/filesinkgui.h
+++ b/plugins/samplesink/filesink/filesinkgui.h
@@ -57,7 +57,6 @@ private:
QString m_fileName;
QTimer m_updateTimer;
QTimer m_statusTimer;
- std::vector m_gains;
DeviceSampleSink* m_deviceSampleSink;
int m_sampleRate;
quint64 m_deviceCenterFrequency; //!< Center frequency in device
diff --git a/plugins/samplesink/filesink/filesinkplugin.h b/plugins/samplesink/filesink/filesinkplugin.h
index dd9316560..c57ba173c 100644
--- a/plugins/samplesink/filesink/filesinkplugin.h
+++ b/plugins/samplesink/filesink/filesinkplugin.h
@@ -37,7 +37,7 @@ public:
void initPlugin(PluginAPI* pluginAPI);
virtual SamplingDevices enumSampleSinks();
- virtual PluginGUI* createSampleSinkPluginGUI(const QString& sourceId, QWidget **widget, DeviceSinkAPI *deviceAPI);
+ virtual PluginGUI* createSampleSinkPluginGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI);
static const QString m_hardwareID;
static const QString m_deviceTypeID;
diff --git a/plugins/samplesource/bladerfinput/bladerfinputgui.cpp b/plugins/samplesource/bladerfinput/bladerfinputgui.cpp
index 4f3afe5ae..01c384f36 100644
--- a/plugins/samplesource/bladerfinput/bladerfinputgui.cpp
+++ b/plugins/samplesource/bladerfinput/bladerfinputgui.cpp
@@ -465,69 +465,3 @@ unsigned int BladerfInputGui::getXb200Index(bool xb_200, bladerf_xb200_path xb20
}
}
-unsigned int BladerfSampleRates::m_rates[] = {1536, 1600, 2000, 2304, 2400, 3072, 3200, 4608, 4800, 6144, 7680, 9216, 9600, 10752, 12288, 18432, 19200, 24576, 30720, 36864, 39936};
-unsigned int BladerfSampleRates::m_nb_rates = 21;
-
-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 BladerfSampleRates::getNbRates()
-{
- return BladerfSampleRates::m_nb_rates;
-}
-
-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/2000 == m_halfbw[i])
- {
- return i;
- }
- }
-
- return 0;
-}
-
-unsigned int BladerfBandwidths::getNbBandwidths()
-{
- return BladerfBandwidths::m_nb_halfbw;
-}
-
diff --git a/plugins/samplesource/bladerfinput/bladerfinputgui.h b/plugins/samplesource/bladerfinput/bladerfinputgui.h
index 6d3a14127..1e6cc8939 100644
--- a/plugins/samplesource/bladerfinput/bladerfinputgui.h
+++ b/plugins/samplesource/bladerfinput/bladerfinputgui.h
@@ -27,7 +27,6 @@ class FileRecord;
namespace Ui {
class BladerfInputGui;
- class BladerfSampleRates;
}
class BladerfInputGui : public QWidget, public PluginGUI {
@@ -86,24 +85,4 @@ private slots:
void updateStatus();
};
-class BladerfSampleRates {
-public:
- static unsigned int getRate(unsigned int rate_index);
- static unsigned int getRateIndex(unsigned int rate);
- static unsigned int getNbRates();
-private:
- static unsigned int m_rates[21];
- static unsigned int m_nb_rates;
-};
-
-class BladerfBandwidths {
-public:
- static unsigned int getBandwidth(unsigned int bandwidth_index);
- static unsigned int getBandwidthIndex(unsigned int bandwidth);
- static unsigned int getNbBandwidths();
-private:
- static unsigned int m_halfbw[16];
- static unsigned int m_nb_halfbw;
-};
-
#endif // INCLUDE_BLADERFINPUTGUI_H