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 +
gui/valuedial.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + + + +
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