From 85ed39c767b167137dd1782c610992d152cc2bab Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 8 Jan 2017 04:13:20 +0100 Subject: [PATCH] HackRF output plugin: compiles --- debian/changelog | 6 + plugins/samplesink/CMakeLists.txt | 6 + .../samplesink/hackrfoutput/CMakeLists.txt | 73 +++ .../samplesink/hackrfoutput/hackrfoutput.cpp | 415 ++++++++++++++ .../samplesink/hackrfoutput/hackrfoutput.h | 98 ++++ .../hackrfoutput/hackrfoutputgui.cpp | 358 ++++++++++++ .../samplesink/hackrfoutput/hackrfoutputgui.h | 94 ++++ .../hackrfoutput/hackrfoutputgui.ui | 512 ++++++++++++++++++ .../hackrfoutput/hackrfoutputplugin.cpp | 131 +++++ .../hackrfoutput/hackrfoutputplugin.h | 48 ++ .../hackrfoutput/hackrfoutputsettings.cpp | 87 +++ .../hackrfoutput/hackrfoutputsettings.h | 39 ++ .../hackrfoutput/hackrfoutputthread.cpp | 152 ++++++ .../hackrfoutput/hackrfoutputthread.h | 63 +++ .../samplesource/hackrfinput/hackrfinput.cpp | 14 +- .../hackrfinput/hackrfinputplugin.cpp | 2 +- sdrbase/gui/aboutdialog.ui | 2 +- sdrbase/mainwindow.cpp | 4 +- 18 files changed, 2094 insertions(+), 10 deletions(-) create mode 100644 plugins/samplesink/hackrfoutput/CMakeLists.txt create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutput.cpp create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutput.h create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputgui.h create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputgui.ui create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputplugin.h create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputsettings.h create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputthread.cpp create mode 100644 plugins/samplesink/hackrfoutput/hackrfoutputthread.h diff --git a/debian/changelog b/debian/changelog index 1b135f644..be0c05435 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +sdrangel (3.1.0-1) unstable; urgency=medium + + * HackRF Tx support + + -- Edouard Griffiths, F4EXB Sun, 08 Jan 2017 23:14:18 +0100 + sdrangel (3.0.1-1) unstable; urgency=medium * Fixed audio preferences dialog and handling diff --git a/plugins/samplesink/CMakeLists.txt b/plugins/samplesink/CMakeLists.txt index 5d5c860f3..24e9721a3 100644 --- a/plugins/samplesink/CMakeLists.txt +++ b/plugins/samplesink/CMakeLists.txt @@ -7,8 +7,14 @@ if(LIBUSB_FOUND AND LIBBLADERF_FOUND) add_subdirectory(bladerfoutput) endif(LIBUSB_FOUND AND LIBBLADERF_FOUND) +find_package(LibHACKRF) +if(LIBUSB_FOUND AND LIBHACKRF_FOUND) + add_subdirectory(hackrfoutput) +endif(LIBUSB_FOUND AND LIBHACKRF_FOUND) + if (BUILD_DEBIAN) add_subdirectory(bladerfoutput) + add_subdirectory(hackrfoutput) endif (BUILD_DEBIAN) add_subdirectory(filesink) diff --git a/plugins/samplesink/hackrfoutput/CMakeLists.txt b/plugins/samplesink/hackrfoutput/CMakeLists.txt new file mode 100644 index 000000000..cd9f2f590 --- /dev/null +++ b/plugins/samplesink/hackrfoutput/CMakeLists.txt @@ -0,0 +1,73 @@ +project(hackrfoutput) + +set(hackrfoutput_SOURCES + hackrfoutputgui.cpp + hackrfoutput.cpp + hackrfoutputplugin.cpp + hackrfoutputsettings.cpp + hackrfoutputthread.cpp +) + +set(hackrfoutput_HEADERS + hackrfoutputgui.h + hackrfoutput.h + hackrfoutputplugin.h + hackrfoutputsettings.h + hackrfoutputthread.h +) + +set(hackrfoutput_FORMS + hackrfoutputgui.ui +) + +if (BUILD_DEBIAN) +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/devices + ${LIBHACKRFSRC} + ${LIBHACKRFSRC}/libhackrf/src +) +else (BUILD_DEBIAN) +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/devices + ${LIBHACKRF_INCLUDE_DIR} +) +endif (BUILD_DEBIAN) + +#include(${QT_USE_FILE}) +#add_definitions(${QT_DEFINITIONS}) +add_definitions("${QT_DEFINITIONS} -DLIBHACKRF_DYN_RATES") +add_definitions(-DQT_PLUGIN) +add_definitions(-DQT_SHARED) + +#qt4_wrap_cpp(hackrfoutput_HEADERS_MOC ${hackrfoutput_HEADERS}) +qt5_wrap_ui(hackrfoutput_FORMS_HEADERS ${hackrfoutput_FORMS}) + +add_library(outputhackrf SHARED + ${hackrfoutput_SOURCES} + ${hackrfoutput_HEADERS_MOC} + ${hackrfoutput_FORMS_HEADERS} +) + +if (BUILD_DEBIAN) +target_link_libraries(outputhackrf + ${QT_LIBRARIES} + hackrf + sdrbase + hackrfdevice +) +else (BUILD_DEBIAN) +target_link_libraries(outputhackrf + ${QT_LIBRARIES} + ${LIBHACKRF_LIBRARIES} + sdrbase + hackrfdevice +) +endif (BUILD_DEBIAN) + +qt5_use_modules(outputhackrf Core Widgets) + +install(TARGETS outputhackrf DESTINATION lib/plugins/samplesink) diff --git a/plugins/samplesink/hackrfoutput/hackrfoutput.cpp b/plugins/samplesink/hackrfoutput/hackrfoutput.cpp new file mode 100644 index 000000000..de298fc03 --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutput.cpp @@ -0,0 +1,415 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 "hackrfoutput.h" + +#include +#include +#include + +#include "util/simpleserializer.h" +#include "dsp/dspcommands.h" +#include "dsp/dspengine.h" +#include "device/devicesourceapi.h" +#include "device/devicesinkapi.h" + + +#include "hackrfoutputgui.h" +#include "hackrfoutputthread.h" + +MESSAGE_CLASS_DEFINITION(HackRFOutput::MsgConfigureHackRF, Message) +MESSAGE_CLASS_DEFINITION(HackRFOutput::MsgReportHackRF, Message) + +HackRFOutput::HackRFOutput(DeviceSinkAPI *deviceAPI) : + m_deviceAPI(deviceAPI), + m_settings(), + m_dev(0), + m_hackRFThread(0), + m_deviceDescription("HackRFOutput") +{ + m_deviceAPI->setBuddySharedPtr(&m_sharedParams); +} + +HackRFOutput::~HackRFOutput() +{ + if (m_dev != 0) + { + stop(); + } + + m_deviceAPI->setBuddySharedPtr(0); +} + +bool HackRFOutput::init(const Message& cmd) +{ + return false; +} + +bool HackRFOutput::start(int device) +{ +// QMutexLocker mutexLocker(&m_mutex); + if (m_dev != 0) + { + stop(); + } + +// hackrf_error rc; +// +// rc = (hackrf_error) hackrf_init(); +// +// if (rc != HACKRF_SUCCESS) +// { +// qCritical("HackRFInput::start: failed to initiate HackRF library %s", hackrf_error_name(rc)); +// } + + m_sampleSourceFifo.resize(m_settings.m_devSampleRate); // 1s long + + + if (m_deviceAPI->getSourceBuddies().size() > 0) + { + DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0]; + DeviceHackRFParams *buddySharedParams = (DeviceHackRFParams *) buddy->getBuddySharedPtr(); + + if (buddySharedParams == 0) + { + qCritical("HackRFOutput::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("HackRFOutput::start: could not get HackRF handle from buddy"); + return false; + } + } + else // Rx is not running so Tx opens device and takes ownership + { + if ((m_dev = DeviceHackRF::open_hackrf(device)) == 0) + { + qCritical("HackRFOutput::start: could not open HackRF #%d", device); + return false; + } + + m_sharedParams.m_dev = m_dev; + } + } + else // No Rx part open so Tx opens device and takes ownership + { + if ((m_dev = DeviceHackRF::open_hackrf(device)) == 0) + { + qCritical("HackRFOutput::start: could not open HackRF #%d", device); + return false; + } + + m_sharedParams.m_dev = m_dev; + } + + if((m_hackRFThread = new HackRFOutputThread(m_dev, &m_sampleSourceFifo)) == 0) + { + qFatal("HackRFOutput::start: out of memory"); + stop(); + return false; + } + +// mutexLocker.unlock(); + + applySettings(m_settings, true); + + m_hackRFThread->startWork(); + + qDebug("HackRFOutput::start: started"); + + return true; +} + +void HackRFOutput::stop() +{ + qDebug("HackRFOutput::stop"); +// QMutexLocker mutexLocker(&m_mutex); + + if(m_hackRFThread != 0) + { + m_hackRFThread->stopWork(); + delete m_hackRFThread; + m_hackRFThread = 0; + } + + if(m_dev != 0) + { + hackrf_stop_tx(m_dev); + } + + if (m_deviceAPI->getSourceBuddies().size() > 0) + { + DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0]; + DeviceHackRFParams *buddySharedParams = (DeviceHackRFParams *) 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 HackRF + { + hackrf_close(m_dev); + hackrf_exit(); // TODO: this may not work if several HackRF Devices are running concurrently. It should be handled globally in the application + } + } + } + else // No Rx part open + { + if(m_dev != 0) // close HackRF + { + hackrf_close(m_dev); + hackrf_exit(); // TODO: this may not work if several HackRF Devices are running concurrently. It should be handled globally in the application + } + } + + m_sharedParams.m_dev = 0; + m_dev = 0; +} + +const QString& HackRFOutput::getDeviceDescription() const +{ + return m_deviceDescription; +} + +int HackRFOutput::getSampleRate() const +{ + int rate = m_settings.m_devSampleRate; + return (rate / (1<(freq_hz)); + + if (rc != HACKRF_SUCCESS) + { + qWarning("HackRFOutput::setCenterFrequency: could not frequency to %llu Hz", freq_hz); + } + else + { + qWarning("HackRFOutput::setCenterFrequency: frequency set to %llu Hz", freq_hz); + } +} + +bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool force) +{ +// QMutexLocker mutexLocker(&m_mutex); + + bool forwardChange = false; + hackrf_error rc; + + qDebug() << "HackRFOutput::applySettings"; + + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) + { + m_settings.m_devSampleRate = settings.m_devSampleRate; + forwardChange = true; + + if (m_dev != 0) + { + rc = (hackrf_error) hackrf_set_sample_rate_manual(m_dev, m_settings.m_devSampleRate, 1); + + if (rc != HACKRF_SUCCESS) + { + qCritical("HackRFOutput::applySettings: could not set sample rate to %d S/s: %s", + m_settings.m_devSampleRate, + hackrf_error_name(rc)); + } + else + { + qDebug("HackRFOutput::applySettings: sample rate set to %d S/s", + m_settings.m_devSampleRate); + m_hackRFThread->setSamplerate(m_settings.m_devSampleRate); + } + } + } + + if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) + { + m_settings.m_log2Interp = settings.m_log2Interp; + forwardChange = true; + + if(m_dev != 0) + { + m_hackRFThread->setLog2Interpolation(m_settings.m_log2Interp); + qDebug() << "HackRFOutput: set interpolation to " << (1<getDeviceInputMessageQueue()->push(notif); + } + + return true; +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutput.h b/plugins/samplesink/hackrfoutput/hackrfoutput.h new file mode 100644 index 000000000..f3559c2bb --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutput.h @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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_HACKRFOUTPUT_H +#define INCLUDE_HACKRFOUTPUT_H + +#include "dsp/devicesamplesink.h" +#include "libhackrf/hackrf.h" +#include + +#include "hackrf/devicehackrf.h" +#include "hackrf/devicehackrfparam.h" +#include "hackrfoutputsettings.h" + +class DeviceSinkAPI; +class HackRFOutputThread; + +class HackRFOutput : public DeviceSampleSink { +public: + + class MsgConfigureHackRF : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const HackRFOutputSettings& getSettings() const { return m_settings; } + + static MsgConfigureHackRF* create(const HackRFOutputSettings& settings) + { + return new MsgConfigureHackRF(settings); + } + + private: + HackRFOutputSettings m_settings; + + MsgConfigureHackRF(const HackRFOutputSettings& settings) : + Message(), + m_settings(settings) + { } + }; + + class MsgReportHackRF : public Message { + MESSAGE_CLASS_DECLARATION + + public: + + static MsgReportHackRF* create() + { + return new MsgReportHackRF(); + } + + protected: + + MsgReportHackRF() : + Message() + { } + }; + + HackRFOutput(DeviceSinkAPI *deviceAPI); + virtual ~HackRFOutput(); + + 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 HackRFOutputSettings& settings, bool force); +// hackrf_device *open_hackrf_from_sequence(int sequence); + void setCenterFrequency(quint64 freq); + + DeviceSinkAPI *m_deviceAPI; + QMutex m_mutex; + HackRFOutputSettings m_settings; + struct hackrf_device* m_dev; + HackRFOutputThread* m_hackRFThread; + QString m_deviceDescription; + DeviceHackRFParams m_sharedParams; +}; + +#endif // INCLUDE_HACKRFINPUT_H diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp new file mode 100644 index 000000000..872f8dfd4 --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp @@ -0,0 +1,358 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 "hackrfoutputgui.h" + +#include +#include + +#include + +#include "gui/colormapper.h" +#include "gui/glspectrum.h" +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "device/devicesinkapi.h" +#include "hackrf/devicehackrfvalues.h" + +#include "ui_hackrfoutputgui.h" + +HackRFOutputGui::HackRFOutputGui(DeviceSinkAPI *deviceAPI, QWidget* parent) : + QWidget(parent), + ui(new Ui::HackRFOutputGui), + m_deviceAPI(deviceAPI), + m_settings(), + m_deviceSampleSink(0), + m_lastEngineState((DSPDeviceSinkEngine::State)-1) +{ + ui->setupUi(this); + ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); + ui->centerFrequency->setValueRange(7, 0U, 7250000U); + + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); + connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); + m_statusTimer.start(500); + + displaySettings(); + + m_deviceSampleSink = new HackRFOutput(m_deviceAPI); + + displaySampleRates(); + displayBandwidths(); + + m_deviceAPI->setSink(m_deviceSampleSink); + + connect(m_deviceAPI->getDeviceOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleDSPMessages()), Qt::QueuedConnection); +} + +HackRFOutputGui::~HackRFOutputGui() +{ + delete m_deviceSampleSink; // Valgrind memcheck + delete ui; +} + +void HackRFOutputGui::destroy() +{ + delete this; +} + +void HackRFOutputGui::setName(const QString& name) +{ + setObjectName(name); +} + +QString HackRFOutputGui::getName() const +{ + return objectName(); +} + +void HackRFOutputGui::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + sendSettings(); +} + +qint64 HackRFOutputGui::getCenterFrequency() const +{ + return m_settings.m_centerFrequency; +} + +void HackRFOutputGui::setCenterFrequency(qint64 centerFrequency) +{ + m_settings.m_centerFrequency = centerFrequency; + displaySettings(); + sendSettings(); +} + +QByteArray HackRFOutputGui::serialize() const +{ + return m_settings.serialize(); +} + +bool HackRFOutputGui::deserialize(const QByteArray& data) +{ + if(m_settings.deserialize(data)) + { + displaySettings(); + sendSettings(); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool HackRFOutputGui::handleMessage(const Message& message) +{ + if (HackRFOutput::MsgReportHackRF::match(message)) + { + displaySettings(); + return true; + } + else + { + return false; + } +} + +void HackRFOutputGui::handleDSPMessages() +{ + Message* message; + + while ((message = m_deviceAPI->getDeviceOutputMessageQueue()->pop()) != 0) + { + qDebug("HackRFOutputGui::handleDSPMessages: message: %s", message->getIdentifier()); + + if (DSPSignalNotification::match(*message)) + { + DSPSignalNotification* notif = (DSPSignalNotification*) message; + m_sampleRate = notif->getSampleRate(); + m_deviceCenterFrequency = notif->getCenterFrequency(); + qDebug("HackRFOutputGui::handleDSPMessages: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency()); + updateSampleRateAndFrequency(); + + delete message; + } + } +} + +void HackRFOutputGui::updateSampleRateAndFrequency() +{ + m_deviceAPI->getSpectrum()->setSampleRate(m_sampleRate); + m_deviceAPI->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency); + ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000)); +} + +void HackRFOutputGui::displaySettings() +{ + ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); + + ui->LOppm->setValue(m_settings.m_LOppmTenths); + ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1))); + + unsigned int sampleRateIndex = HackRFSampleRates::getRateIndex(m_settings.m_devSampleRate/1000); + ui->sampleRate->setCurrentIndex(sampleRateIndex); + + ui->biasT->setChecked(m_settings.m_biasT); + + ui->interp->setCurrentIndex(m_settings.m_log2Interp); + + ui->lnaExt->setChecked(m_settings.m_lnaExt); + ui->vgaGainText->setText(tr("%1dB").arg(m_settings.m_vgaGain)); + ui->vga->setValue(m_settings.m_vgaGain); + + unsigned int bandwidthIndex = HackRFBandwidths::getBandwidthIndex(m_settings.m_bandwidth/1000); + ui->bbFilter->setCurrentIndex(bandwidthIndex); + + ui->txvgaGainText->setText(tr("%1dB").arg(m_settings.m_txvgaGain)); + ui->txvga->setValue(m_settings.m_txvgaGain); +} + +void HackRFOutputGui::displaySampleRates() +{ + int savedIndex = HackRFSampleRates::getRateIndex(m_settings.m_devSampleRate/1000); + ui->sampleRate->blockSignals(true); + ui->sampleRate->clear(); + + for (int i = 0; i < HackRFSampleRates::m_nb_rates; i++) + { + ui->sampleRate->addItem(QString("%1M").arg(QString::number(HackRFSampleRates::m_rates_k[i]/1000.0, 'f', 1))); + } + + ui->sampleRate->blockSignals(false); + + if (savedIndex < HackRFSampleRates::m_nb_rates) + { + ui->sampleRate->setCurrentIndex(savedIndex); + } + else + { + ui->sampleRate->setCurrentIndex((int) HackRFSampleRates::m_nb_rates-1); + } +} + +void HackRFOutputGui::displayBandwidths() +{ + int savedIndex = HackRFBandwidths::getBandwidthIndex(m_settings.m_bandwidth/1000); + ui->bbFilter->blockSignals(true); + ui->bbFilter->clear(); + + for (int i = 0; i < HackRFBandwidths::m_nb_bw; i++) + { + ui->bbFilter->addItem(QString("%1M").arg(QString::number(HackRFBandwidths::m_bw_k[i]/1000.0, 'f', 2))); + } + + ui->bbFilter->blockSignals(false); + + if (savedIndex < HackRFBandwidths::m_nb_bw) + { + ui->bbFilter->setCurrentIndex(savedIndex); + } + else + { + ui->bbFilter->setCurrentIndex((int) HackRFBandwidths::m_nb_bw-1); + } +} + +void HackRFOutputGui::sendSettings() +{ + if(!m_updateTimer.isActive()) + m_updateTimer.start(100); +} + +void HackRFOutputGui::on_centerFrequency_changed(quint64 value) +{ + m_settings.m_centerFrequency = value * 1000; + sendSettings(); +} + +void HackRFOutputGui::on_LOppm_valueChanged(int value) +{ + m_settings.m_LOppmTenths = value; + ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1))); + sendSettings(); +} + +void HackRFOutputGui::on_sampleRate_currentIndexChanged(int index) +{ + int newrate = HackRFSampleRates::getRate(index); + m_settings.m_devSampleRate = newrate * 1000; + sendSettings(); +} + +void HackRFOutputGui::on_bbFilter_currentIndexChanged(int index) +{ + int newBandwidth = HackRFBandwidths::getBandwidth(index); + m_settings.m_bandwidth = newBandwidth * 1000; + sendSettings(); +} + +void HackRFOutputGui::on_biasT_stateChanged(int state) +{ + m_settings.m_biasT = (state == Qt::Checked); + sendSettings(); +} + +void HackRFOutputGui::on_lnaExt_stateChanged(int state) +{ + m_settings.m_lnaExt = (state == Qt::Checked); + sendSettings(); +} + +void HackRFOutputGui::on_interp_currentIndexChanged(int index) +{ + if ((index <0) || (index > 6)) + return; + m_settings.m_log2Interp = index; + sendSettings(); +} + +void HackRFOutputGui::on_vga_valueChanged(int value) +{ + if ((value < 0) || (value > 62)) + return; + + ui->vgaGainText->setText(tr("%1dB").arg(value)); + m_settings.m_vgaGain = value; + sendSettings(); +} + +void HackRFOutputGui::on_txvga_valueChanged(int value) +{ + if ((value < 0) || (value > 47)) + return; + + ui->txvgaGainText->setText(tr("%1dB").arg(value)); + m_settings.m_vgaGain = value; + sendSettings(); +} + +void HackRFOutputGui::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 HackRFOutputGui::updateHardware() +{ + qDebug() << "HackRFOutputGui::updateHardware"; + HackRFOutput::MsgConfigureHackRF* message = HackRFOutput::MsgConfigureHackRF::create(m_settings); + m_deviceSampleSink->getInputMessageQueue()->push(message); + m_updateTimer.stop(); +} + +void HackRFOutputGui::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 : green; }"); + break; + case DSPDeviceSinkEngine::StError: + ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); + QMessageBox::information(this, tr("Message"), m_deviceAPI->errorMessage()); + break; + default: + break; + } + + m_lastEngineState = state; + } +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h new file mode 100644 index 000000000..8d0c525bd --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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_HACKRFOUTPUTGUI_H +#define INCLUDE_HACKRFOUTPUTGUI_H + +#include + +#include "plugin/plugingui.h" +#include "hackrfoutput.h" + +#define HACKRF_MAX_DEVICE (32) + +class DeviceSinkAPI; +class DeviceSampleSink; + +namespace Ui { + class HackRFOutputGui; +} + +class HackRFOutputGui : public QWidget, public PluginGUI { + Q_OBJECT + +public: + typedef enum + { + HACKRF_IMGREJ_BYPASS = 0, + HACKRF_IMGREJ_LOWPASS, + HACKRF_IMGREJ_HIGHPASS, + HACKRF_IMGREJ_NB + } HackRFImgRejValue; + + explicit HackRFOutputGui(DeviceSinkAPI *deviceAPI, QWidget* parent = NULL); + virtual ~HackRFOutputGui(); + 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::HackRFOutputGui* ui; + + DeviceSinkAPI* m_deviceAPI; + HackRFOutputSettings m_settings; + QTimer m_updateTimer; + QTimer m_statusTimer; + DeviceSampleSink* m_deviceSampleSink; + int m_sampleRate; + quint64 m_deviceCenterFrequency; //!< Center frequency in device + int m_lastEngineState; + + void displaySettings(); + void displaySampleRates(); + void displayBandwidths(); + void sendSettings(); + void updateSampleRateAndFrequency(); + +private slots: + void handleDSPMessages(); + void on_centerFrequency_changed(quint64 value); + void on_LOppm_valueChanged(int value); + void on_sampleRate_currentIndexChanged(int index); + void on_biasT_stateChanged(int state); + void on_interp_currentIndexChanged(int index); + void on_lnaExt_stateChanged(int state); + void on_vga_valueChanged(int value); + void on_bbFilter_currentIndexChanged(int index); + void on_txvga_valueChanged(int value); + void on_startStop_toggled(bool checked); + void updateHardware(); + void updateStatus(); +}; + +#endif // INCLUDE_HACKRFOUTPUTGUI_H diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui b/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui new file mode 100644 index 000000000..ddc8277d5 --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui @@ -0,0 +1,512 @@ + + + HackRFOutputGui + + + + 0 + 0 + 260 + 210 + + + + + 0 + 0 + + + + + 260 + 210 + + + + + Sans Serif + 9 + + + + HackRF + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + + + + + start/stop acquisition + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + + + + + + 60 + 0 + + + + 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 + + + + + + + + + + 3 + + + + + LO correction ppm + + + LO ppm + + + + + + + Local Oscullator ppm correction + + + -100 + + + 100 + + + 1 + + + Qt::Horizontal + + + + + + + 0.0 + + + + + + + + + Qt::Horizontal + + + + + + + + + Int + + + + + + + Activate antenna bias tee + + + Qt::RightToLeft + + + Bias T + + + + + + + Extra LNA +14dB + + + Qt::RightToLeft + + + RF Amp + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 55 + 16777215 + + + + Decimation factor + + + 0 + + + + 1 + + + + + 2 + + + + + + + + + + 3 + + + + + + 0 + 0 + + + + Rate + + + + + + + Device sample rate + + + + + + + BBF + + + + + + + RF bandpas filter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + + + + 3 + + + + + + 0 + 0 + + + + + 42 + 0 + + + + VGA + + + + + + + true + + + LNA gain dB + + + 62 + + + 2 + + + 2 + + + 30 + + + Qt::Horizontal + + + + + + + + 40 + 0 + + + + 0dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + 3 + + + + + + 42 + 0 + + + + TxVGA + + + + + + + VGA gain dB + + + 47 + + + 1 + + + 1 + + + 22 + + + Qt::Horizontal + + + + + + + + 40 + 0 + + + + 0dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + + + +
diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp new file mode 100644 index 000000000..45bad6b7c --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 "hackrfoutputplugin.h" + +#include +#include +#include "libhackrf/hackrf.h" + +#include "device/devicesourceapi.h" + +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" + +#include "hackrfoutputgui.h" + +const PluginDescriptor HackRFOutputPlugin::m_pluginDescriptor = { + QString("HackRF Output"), + QString("3.1.0"), + QString("(c) Edouard Griffiths, F4EXB"), + QString("https://github.com/f4exb/sdrangel"), + true, + QString("https://github.com/f4exb/sdrangel") +}; + +const QString HackRFOutputPlugin::m_hardwareID = "HackRF"; +const QString HackRFOutputPlugin::m_deviceTypeID = HACKRFOUTPUT_DEVICE_TYPE_ID; + +HackRFOutputPlugin::HackRFOutputPlugin(QObject* parent) : + QObject(parent) +{ +} + +const PluginDescriptor& HackRFOutputPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void HackRFOutputPlugin::initPlugin(PluginAPI* pluginAPI) +{ + pluginAPI->registerSampleSink(m_deviceTypeID, this); +} + +PluginInterface::SamplingDevices HackRFOutputPlugin::enumSampleSinks() +{ + hackrf_error rc = (hackrf_error) hackrf_init(); + + if (rc != HACKRF_SUCCESS) + { + qCritical("HackRFOutputPlugin::enumSampleSinks: failed to initiate HackRF library: %s", hackrf_error_name(rc)); + } + + SamplingDevices result; + hackrf_device_list_t *hackrf_devices = hackrf_device_list(); + hackrf_device *hackrf_ptr; + read_partid_serialno_t read_partid_serialno; + int i; + + for (i=0; i < hackrf_devices->devicecount; i++) + { + rc = (hackrf_error) hackrf_device_list_open(hackrf_devices, i, &hackrf_ptr); + + if (rc == HACKRF_SUCCESS) + { + qDebug("HackRFOutputPlugin::enumSampleSinks: try to enumerate HackRF device #%d", i); + + rc = (hackrf_error) hackrf_board_partid_serialno_read(hackrf_ptr, &read_partid_serialno); + + if (rc != HACKRF_SUCCESS) + { + qDebug("HackRFOutputPlugin::enumSampleSinks: failed to read serial no: %s", hackrf_error_name(rc)); + hackrf_close(hackrf_ptr); + continue; // next + } + + uint32_t serial_msb = read_partid_serialno.serial_no[2]; + uint32_t serial_lsb = read_partid_serialno.serial_no[3]; + + QString serial_str = QString::number(serial_msb, 16) + QString::number(serial_lsb, 16); + uint64_t serial_num = (((uint64_t) serial_msb)<<32) + serial_lsb; + QString displayedName(QString("HackRF[%1] %2").arg(i).arg(serial_str)); + + result.append(SamplingDevice(displayedName, + m_hardwareID, + m_deviceTypeID, + serial_str, + i)); + + qDebug("HackRFOutputPlugin::enumSampleSinks: enumerated HackRF device #%d", i); + + hackrf_close(hackrf_ptr); + } + else + { + qDebug("HackRFOutputPlugin::enumSampleSinks: failed to enumerate HackRF device #%d: %s", i, hackrf_error_name(rc)); + } + } + + hackrf_device_list_free(hackrf_devices); + rc = (hackrf_error) hackrf_exit(); + qDebug("HackRFOutputPlugin::enumSampleSinks: hackrf_exit: %s", hackrf_error_name(rc)); + + return result; +} + +PluginGUI* HackRFOutputPlugin::createSampleSinkPluginGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) +{ + if(sinkId == m_deviceTypeID) + { + HackRFOutputGui* gui = new HackRFOutputGui(deviceAPI); + *widget = gui; + return gui; + } + else + { + return 0; + } +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h new file mode 100644 index 000000000..3e824c81a --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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_HACKRFOUTPUTPLUGIN_H +#define INCLUDE_HACKRFOUTPUTPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +#define HACKRFOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesource.hackrfoutput" + +class PluginAPI; + +class HackRFOutputPlugin : public QObject, public PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID HACKRFOUTPUT_DEVICE_TYPE_ID) + +public: + explicit HackRFOutputPlugin(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_HACKRFOUTPUTPLUGIN_H diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp new file mode 100644 index 000000000..a664d4d86 --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 "hackrfoutputsettings.h" + +#include +#include "util/simpleserializer.h" + + +HackRFOutputSettings::HackRFOutputSettings() +{ + resetToDefaults(); +} + +void HackRFOutputSettings::resetToDefaults() +{ + m_centerFrequency = 435000 * 1000; + m_LOppmTenths = 0; + m_devSampleRate = 2400000; + m_biasT = false; + m_log2Interp = 0; + m_lnaExt = false; + m_vgaGain = 30; + m_bandwidth = 1750000; + m_txvgaGain = 22; +} + +QByteArray HackRFOutputSettings::serialize() const +{ + SimpleSerializer s(1); + + s.writeS32(1, m_LOppmTenths); + s.writeU32(2, m_devSampleRate); + s.writeBool(3, m_biasT); + s.writeU32(4, m_log2Interp); + s.writeBool(5, m_lnaExt); + s.writeU32(6, m_vgaGain); + s.writeU32(7, m_bandwidth); + s.writeU32(8, m_txvgaGain); + + return s.final(); +} + +bool HackRFOutputSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + int intval; + + d.readS32(1, &m_LOppmTenths, 0); + d.readU32(2, &m_devSampleRate, 2400000); + d.readBool(3, &m_biasT, false); + d.readU32(4, &m_log2Interp, 0); + d.readBool(5, &m_lnaExt, false); + d.readU32(6, &m_vgaGain, 30); + d.readU32(7, &m_bandwidth, 1750000); + d.readU32(8, &m_txvgaGain, 22); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h new file mode 100644 index 000000000..61301053d --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 _HACKRF_HACKRFOUTPUTSETTINGS_H_ +#define _HACKRF_HACKRFOUTPUTSETTINGS_H_ + +#include + +struct HackRFOutputSettings { + quint64 m_centerFrequency; + qint32 m_LOppmTenths; + quint32 m_devSampleRate; + quint32 m_bandwidth; + quint32 m_vgaGain; + quint32 m_txvgaGain; + quint32 m_log2Interp; + bool m_biasT; + bool m_lnaExt; + + HackRFOutputSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + +#endif /* _HACKRF_HACKRFOUTPUTSETTINGS_H_ */ diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputthread.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputthread.cpp new file mode 100644 index 000000000..3686d260f --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputthread.cpp @@ -0,0 +1,152 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 "hackrfoutputthread.h" + +#include +#include + +#include "dsp/samplesourcefifo.h" + +HackRFOutputThread *HackRFOutputThread::m_this = 0; + +HackRFOutputThread::HackRFOutputThread(hackrf_device* dev, SampleSourceFifo* sampleFifo, QObject* parent) : + QThread(parent), + m_running(false), + m_dev(dev), + m_convertBuffer(HACKRF_BLOCKSIZE), + m_sampleFifo(sampleFifo), + m_samplerate(10), + m_log2Interp(0) +{ + m_this = this; +} + +HackRFOutputThread::~HackRFOutputThread() +{ + stopWork(); + m_this = 0; +} + +void HackRFOutputThread::startWork() +{ + //m_startWaitMutex.lock(); + m_running = true; + start(); + /* + while(!m_running) + m_startWaiter.wait(&m_startWaitMutex, 100); + m_startWaitMutex.unlock();*/ +} + +void HackRFOutputThread::stopWork() +{ + qDebug("HackRFOutputThread::stopWork"); + m_running = false; + wait(); +} + +void HackRFOutputThread::setSamplerate(uint32_t samplerate) +{ + m_samplerate = samplerate; +} + +void HackRFOutputThread::setLog2Interpolation(unsigned int log2Interp) +{ + m_log2Interp = log2Interp; +} + +void HackRFOutputThread::run() +{ + hackrf_error rc; + + //m_running = true; + m_startWaiter.wakeAll(); + + rc = (hackrf_error) hackrf_start_tx(m_dev, tx_callback, NULL); + + if (rc != HACKRF_SUCCESS) + { + qCritical("HackRFOutputThread::run: failed to start HackRF Tx: %s", hackrf_error_name(rc)); + } + else + { + while ((m_running) && (hackrf_is_streaming(m_dev) == HACKRF_TRUE)) + { + sleep(1); + } + } + + rc = (hackrf_error) hackrf_stop_tx(m_dev); + + if (rc == HACKRF_SUCCESS) + { + qDebug("HackRFOutputThread::run: stopped HackRF Tx"); + } + else + { + qDebug("HackRFOutputThread::run: failed to stop HackRF Tx: %s", hackrf_error_name(rc)); + } + + //m_running = false; +} + +// Interpolate according to specified log2 (ex: log2=4 => interp=16) +void HackRFOutputThread::callback(qint16* buf, qint32 len) +{ + SampleVector::iterator beginRead; + m_sampleFifo->readAdvance(beginRead, len/(1<valid_length; + m_this->callback((qint16 *) transfer->buffer, bytes_to_write); + return 0; +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputthread.h b/plugins/samplesink/hackrfoutput/hackrfoutputthread.h new file mode 100644 index 000000000..ec2451e23 --- /dev/null +++ b/plugins/samplesink/hackrfoutput/hackrfoutputthread.h @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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_HACKRFOUTPUTTHREAD_H +#define INCLUDE_HACKRFOUTPUTTHREAD_H + +#include +#include +#include +#include + +#include "dsp/samplesourcefifo.h" +#include "dsp/interpolators.h" + +#define HACKRF_BLOCKSIZE (1<<17) + +class HackRFOutputThread : public QThread { + Q_OBJECT + +public: + HackRFOutputThread(hackrf_device* dev, SampleSourceFifo* sampleFifo, QObject* parent = NULL); + ~HackRFOutputThread(); + + void startWork(); + void stopWork(); + void setSamplerate(uint32_t samplerate); + void setLog2Interpolation(unsigned int log2_interp); + +private: + QMutex m_startWaitMutex; + QWaitCondition m_startWaiter; + bool m_running; + + hackrf_device* m_dev; + qint16 m_buf[2*HACKRF_BLOCKSIZE]; + SampleVector m_convertBuffer; + SampleSourceFifo* m_sampleFifo; + + int m_samplerate; + unsigned int m_log2Interp; + static HackRFOutputThread *m_this; + + Interpolators m_interpolators; + + void run(); + void callback(qint16* buf, qint32 len); + static int tx_callback(hackrf_transfer* transfer); +}; + +#endif // INCLUDE_HACKRFOUTPUTTHREAD_H diff --git a/plugins/samplesource/hackrfinput/hackrfinput.cpp b/plugins/samplesource/hackrfinput/hackrfinput.cpp index 001494746..a83d9aa95 100644 --- a/plugins/samplesource/hackrfinput/hackrfinput.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinput.cpp @@ -278,12 +278,12 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) { - forwardChange = true; - m_settings.m_devSampleRate = settings.m_devSampleRate; + m_settings.m_devSampleRate = settings.m_devSampleRate; + forwardChange = true; - if (m_dev != 0) + if (m_dev != 0) { - rc = (hackrf_error) hackrf_set_sample_rate_manual(m_dev, m_settings.m_devSampleRate, 1); + rc = (hackrf_error) hackrf_set_sample_rate_manual(m_dev, m_settings.m_devSampleRate, 1); if (rc != HACKRF_SUCCESS) { @@ -404,9 +404,11 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_bandwidth != settings.m_bandwidth) || force) { - if (m_dev != 0) + m_settings.m_bandwidth = settings.m_bandwidth; + + if (m_dev != 0) { - uint32_t bw_index = hackrf_compute_baseband_filter_bw_round_down_lt(m_settings.m_bandwidth); + uint32_t bw_index = hackrf_compute_baseband_filter_bw_round_down_lt(m_settings.m_bandwidth); rc = (hackrf_error) hackrf_set_baseband_filter_bandwidth(m_dev, bw_index); if (rc != HACKRF_SUCCESS) diff --git a/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp b/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp index 3ec257ca3..051f21948 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp @@ -29,7 +29,7 @@ const PluginDescriptor HackRFInputPlugin::m_pluginDescriptor = { QString("HackRF Input"), - QString("3.0.0"), + QString("3.1.0"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/sdrbase/gui/aboutdialog.ui b/sdrbase/gui/aboutdialog.ui index 3b0306de2..3b0bc580b 100644 --- a/sdrbase/gui/aboutdialog.ui +++ b/sdrbase/gui/aboutdialog.ui @@ -84,7 +84,7 @@ - <html><head/><body><p>Version 3.0.1 - Copyright (C) 2015-2017 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">RTL-SDRangelove</span></a></p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>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; either version 2 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html> + <html><head/><body><p>Version 3.1,0 - Copyright (C) 2015-2017 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">RTL-SDRangelove</span></a></p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>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; either version 2 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html> true diff --git a/sdrbase/mainwindow.cpp b/sdrbase/mainwindow.cpp index 70d2459f5..42b9729bc 100644 --- a/sdrbase/mainwindow.cpp +++ b/sdrbase/mainwindow.cpp @@ -454,9 +454,9 @@ void MainWindow::createStatusBar() { QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR); #if QT_VERSION >= 0x050400 - m_showSystemWidget = new QLabel("SDRangel v3.0.1 " + qtVersionStr + QSysInfo::prettyProductName(), this); + m_showSystemWidget = new QLabel("SDRangel v3.1.0 " + qtVersionStr + QSysInfo::prettyProductName(), this); #else - m_showSystemWidget = new QLabel("SDRangel v3.0.1 " + qtVersionStr, this); + m_showSystemWidget = new QLabel("SDRangel v3.1.0 " + qtVersionStr, this); #endif statusBar()->addPermanentWidget(m_showSystemWidget);