From 5453d63431743c50543e486aa7a770c6b1d40d69 Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 4 Sep 2015 04:10:38 +0200 Subject: [PATCH] Deep redesign: Better support for FCD dongles #6: have two distinct plugins for Pro and Pro+. Only Pro+ is active at the moment --- plugins/samplesource/CMakeLists.txt | 2 +- plugins/samplesource/bladerf/bladerfinput.cpp | 2 - plugins/samplesource/fcdpro/CMakeLists.txt | 22 +- .../fcdpro/{fcdgui.cpp => fcdprogui.cpp} | 44 +-- plugins/samplesource/fcdpro/fcdprogui.h | 53 ++++ .../fcdpro/{fcdgui.ui => fcdprogui.ui} | 6 +- plugins/samplesource/fcdpro/fcdproinput.cpp | 289 ++++++++++++++++++ plugins/samplesource/fcdpro/fcdproinput.h | 93 ++++++ .../{fcdplugin.cpp => fcdproplugin.cpp} | 18 +- .../fcdpro/{fcdplugin.h => fcdproplugin.h} | 8 +- ...fcdserializer.cpp => fcdproserializer.cpp} | 8 +- .../{fcdserializer.h => fcdproserializer.h} | 8 +- .../{fcdthread.cpp => fcdprothread.cpp} | 22 +- plugins/samplesource/fcdpro/fcdprothread.h | 55 ++++ .../samplesource/fcdproplus/CMakeLists.txt | 53 ++++ .../samplesource/fcdproplus/fcdproplusgui.cpp | 154 ++++++++++ .../fcdgui.h => fcdproplus/fcdproplusgui.h} | 15 +- .../samplesource/fcdproplus/fcdproplusgui.ui | 144 +++++++++ .../fcdproplusinput.cpp} | 71 +++-- .../fcdproplusinput.h} | 10 +- .../fcdproplus/fcdproplusplugin.cpp | 74 +++++ .../fcdproplus/fcdproplusplugin.h | 27 ++ .../fcdproplus/fcdproplusserializer.cpp | 68 +++++ .../fcdproplus/fcdproplusserializer.h | 39 +++ .../fcdproplus/fcdproplusthread.cpp | 164 ++++++++++ .../fcdproplusthread.h} | 8 +- 26 files changed, 1333 insertions(+), 124 deletions(-) rename plugins/samplesource/fcdpro/{fcdgui.cpp => fcdprogui.cpp} (67%) create mode 100644 plugins/samplesource/fcdpro/fcdprogui.h rename plugins/samplesource/fcdpro/{fcdgui.ui => fcdprogui.ui} (97%) create mode 100644 plugins/samplesource/fcdpro/fcdproinput.cpp create mode 100644 plugins/samplesource/fcdpro/fcdproinput.h rename plugins/samplesource/fcdpro/{fcdplugin.cpp => fcdproplugin.cpp} (80%) rename plugins/samplesource/fcdpro/{fcdplugin.h => fcdproplugin.h} (75%) rename plugins/samplesource/fcdpro/{fcdserializer.cpp => fcdproserializer.cpp} (89%) rename plugins/samplesource/fcdpro/{fcdserializer.h => fcdproserializer.h} (89%) rename plugins/samplesource/fcdpro/{fcdthread.cpp => fcdprothread.cpp} (89%) create mode 100644 plugins/samplesource/fcdpro/fcdprothread.h create mode 100644 plugins/samplesource/fcdproplus/CMakeLists.txt create mode 100644 plugins/samplesource/fcdproplus/fcdproplusgui.cpp rename plugins/samplesource/{fcdpro/fcdgui.h => fcdproplus/fcdproplusgui.h} (75%) create mode 100644 plugins/samplesource/fcdproplus/fcdproplusgui.ui rename plugins/samplesource/{fcdpro/fcdinput.cpp => fcdproplus/fcdproplusinput.cpp} (75%) rename plugins/samplesource/{fcdpro/fcdinput.h => fcdproplus/fcdproplusinput.h} (94%) create mode 100644 plugins/samplesource/fcdproplus/fcdproplusplugin.cpp create mode 100644 plugins/samplesource/fcdproplus/fcdproplusplugin.h create mode 100644 plugins/samplesource/fcdproplus/fcdproplusserializer.cpp create mode 100644 plugins/samplesource/fcdproplus/fcdproplusserializer.h create mode 100644 plugins/samplesource/fcdproplus/fcdproplusthread.cpp rename plugins/samplesource/{fcdpro/fcdthread.h => fcdproplus/fcdproplusthread.h} (90%) diff --git a/plugins/samplesource/CMakeLists.txt b/plugins/samplesource/CMakeLists.txt index 166353be6..1642e0aaa 100644 --- a/plugins/samplesource/CMakeLists.txt +++ b/plugins/samplesource/CMakeLists.txt @@ -18,7 +18,7 @@ if(LIBUSB_FOUND AND UNIX) FIND_LIBRARY (LIBASOUND asound) endif() if(LIBASOUND AND ASOUNDH) - add_subdirectory(fcdpro) + add_subdirectory(fcdproplus) endif() find_package(LibRTLSDR) diff --git a/plugins/samplesource/bladerf/bladerfinput.cpp b/plugins/samplesource/bladerf/bladerfinput.cpp index 8ed9f9224..5c222786e 100644 --- a/plugins/samplesource/bladerf/bladerfinput.cpp +++ b/plugins/samplesource/bladerf/bladerfinput.cpp @@ -206,8 +206,6 @@ void BladerfInput::stop() bladerf_close(m_dev); m_dev = 0; } - - m_deviceDescription.clear(); } const QString& BladerfInput::getDeviceDescription() const diff --git a/plugins/samplesource/fcdpro/CMakeLists.txt b/plugins/samplesource/fcdpro/CMakeLists.txt index 371105607..5ca0ccdeb 100644 --- a/plugins/samplesource/fcdpro/CMakeLists.txt +++ b/plugins/samplesource/fcdpro/CMakeLists.txt @@ -1,23 +1,23 @@ project(fcdpro) set(fcdpro_SOURCES - fcdgui.cpp - fcdinput.cpp - fcdplugin.cpp - fcdserializer.cpp - fcdthread.cpp + fcdprogui.cpp + fcdproinput.cpp + fcdproplugin.cpp + fcdproserializer.cpp + fcdprothread.cpp ) set(fcdpro_HEADERS - fcdgui.h - fcdinput.h - fcdplugin.h - fcdserializer.h - fcdthread.h + fcdprogui.h + fcdproinput.h + fcdproplugin.h + fcdproserializer.h + fcdprothread.h ) set(fcdpro_FORMS - fcdgui.ui + fcdprogui.ui ) include_directories( diff --git a/plugins/samplesource/fcdpro/fcdgui.cpp b/plugins/samplesource/fcdpro/fcdprogui.cpp similarity index 67% rename from plugins/samplesource/fcdpro/fcdgui.cpp rename to plugins/samplesource/fcdpro/fcdprogui.cpp index f75722c34..1e149a69d 100644 --- a/plugins/samplesource/fcdpro/fcdgui.cpp +++ b/plugins/samplesource/fcdpro/fcdprogui.cpp @@ -1,12 +1,12 @@ -#include "fcdgui.h" -#include "ui_fcdgui.h" +#include "ui_fcdprogui.h" #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "dsp/dspengine.h" +#include "fcdprogui.h" -FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) : +FCDProGui::FCDProGui(PluginAPI* pluginAPI, QWidget* parent) : QWidget(parent), - ui(new Ui::FCDGui), + ui(new Ui::FCDProGui), m_pluginAPI(pluginAPI), m_settings(), m_sampleSource(NULL) @@ -17,48 +17,48 @@ FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) : connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); displaySettings(); - m_sampleSource = new FCDInput(); + m_sampleSource = new FCDProInput(); DSPEngine::instance()->setSource(m_sampleSource); } -FCDGui::~FCDGui() +FCDProGui::~FCDProGui() { delete ui; } -void FCDGui::destroy() +void FCDProGui::destroy() { delete this; } -void FCDGui::setName(const QString& name) +void FCDProGui::setName(const QString& name) { setObjectName(name); } -QString FCDGui::getName() const +QString FCDProGui::getName() const { return objectName(); } -void FCDGui::resetToDefaults() +void FCDProGui::resetToDefaults() { m_settings.resetToDefaults(); displaySettings(); sendSettings(); } -qint64 FCDGui::getCenterFrequency() const +qint64 FCDProGui::getCenterFrequency() const { return m_settings.centerFrequency; } -QByteArray FCDGui::serialize() const +QByteArray FCDProGui::serialize() const { return m_settings.serialize(); } -bool FCDGui::deserialize(const QByteArray& data) +bool FCDProGui::deserialize(const QByteArray& data) { if(m_settings.deserialize(data)) { @@ -73,12 +73,12 @@ bool FCDGui::deserialize(const QByteArray& data) } } -bool FCDGui::handleMessage(const Message& message) +bool FCDProGui::handleMessage(const Message& message) { return false; } -void FCDGui::displaySettings() +void FCDProGui::displaySettings() { ui->centerFrequency->setValue(m_settings.centerFrequency / 1000); ui->checkBoxR->setChecked(m_settings.range); @@ -86,26 +86,26 @@ void FCDGui::displaySettings() ui->checkBoxB->setChecked(m_settings.bias); } -void FCDGui::sendSettings() +void FCDProGui::sendSettings() { if(!m_updateTimer.isActive()) m_updateTimer.start(100); } -void FCDGui::on_centerFrequency_changed(quint64 value) +void FCDProGui::on_centerFrequency_changed(quint64 value) { m_settings.centerFrequency = value * 1000; sendSettings(); } -void FCDGui::updateHardware() +void FCDProGui::updateHardware() { - FCDInput::MsgConfigureFCD* message = FCDInput::MsgConfigureFCD::create(m_settings); + FCDProInput::MsgConfigureFCD* message = FCDProInput::MsgConfigureFCD::create(m_settings); m_sampleSource->getInputMessageQueue()->push(message); m_updateTimer.stop(); } -void FCDGui::on_checkBoxR_stateChanged(int state) +void FCDProGui::on_checkBoxR_stateChanged(int state) { if (state == Qt::Checked) // FIXME: this is for the Pro+ version only! { @@ -125,7 +125,7 @@ void FCDGui::on_checkBoxR_stateChanged(int state) sendSettings(); } -void FCDGui::on_checkBoxG_stateChanged(int state) +void FCDProGui::on_checkBoxG_stateChanged(int state) { if (state == Qt::Checked) { @@ -139,7 +139,7 @@ void FCDGui::on_checkBoxG_stateChanged(int state) sendSettings(); } -void FCDGui::on_checkBoxB_stateChanged(int state) +void FCDProGui::on_checkBoxB_stateChanged(int state) { if (state == Qt::Checked) { diff --git a/plugins/samplesource/fcdpro/fcdprogui.h b/plugins/samplesource/fcdpro/fcdprogui.h new file mode 100644 index 000000000..c8ea1920d --- /dev/null +++ b/plugins/samplesource/fcdpro/fcdprogui.h @@ -0,0 +1,53 @@ +#ifndef INCLUDE_FCDPROGUI_H +#define INCLUDE_FCDPROGUI_H + +#include + +#include "fcdproinput.h" +#include "plugin/plugingui.h" + +class PluginAPI; + +namespace Ui { + class FCDProGui; +} + +class FCDProGui : public QWidget, public PluginGUI { + Q_OBJECT + +public: + explicit FCDProGui(PluginAPI* pluginAPI, QWidget* parent = NULL); + virtual ~FCDProGui(); + void destroy(); + + void setName(const QString& name); + QString getName() const; + + void resetToDefaults(); + qint64 getCenterFrequency() const; + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + + virtual bool handleMessage(const Message& message); + +private: + Ui::FCDProGui* ui; + + PluginAPI* m_pluginAPI; + FCDProInput::Settings m_settings; + QTimer m_updateTimer; + std::vector m_gains; + SampleSource* m_sampleSource; + + void displaySettings(); + void sendSettings(); + +private slots: + void on_centerFrequency_changed(quint64 value); + void on_checkBoxR_stateChanged(int state); + void on_checkBoxG_stateChanged(int state); + void on_checkBoxB_stateChanged(int state); + void updateHardware(); +}; + +#endif // INCLUDE_FCDPROGUI_H diff --git a/plugins/samplesource/fcdpro/fcdgui.ui b/plugins/samplesource/fcdpro/fcdprogui.ui similarity index 97% rename from plugins/samplesource/fcdpro/fcdgui.ui rename to plugins/samplesource/fcdpro/fcdprogui.ui index d20ad55f1..677ec4fc5 100644 --- a/plugins/samplesource/fcdpro/fcdgui.ui +++ b/plugins/samplesource/fcdpro/fcdprogui.ui @@ -1,12 +1,12 @@ - FCDGui - + FCDProGui + 0 0 - 132 + 165 119 diff --git a/plugins/samplesource/fcdpro/fcdproinput.cpp b/plugins/samplesource/fcdpro/fcdproinput.cpp new file mode 100644 index 000000000..a87db3abb --- /dev/null +++ b/plugins/samplesource/fcdpro/fcdproinput.cpp @@ -0,0 +1,289 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +// FIXME: FCD is handled very badly! + +#include +#include +#include +#include "dsp/dspcommands.h" +#include "fcdproinput.h" + +#include "fcdprogui.h" +#include "fcdproserializer.h" +#include "fcdprothread.h" + +MESSAGE_CLASS_DEFINITION(FCDProInput::MsgConfigureFCD, Message) + +/* +const uint16_t FCDInput::m_vendorId = 0x04D8; +const uint16_t FCDInput::m_productId = 0xFB31; +const int FCDInput::m_sampleRate = 192000; +const std::string FCDInput::m_deviceName("hw:CARD=V20"); + +const uint16_t FCDInput::m_productId = 0xFB56; +const int FCDInput::m_sampleRate = 96000; +const std::string FCDInput::m_deviceName("hw:CARD=V10"); +*/ + +FCDProInput::Settings::Settings() : + centerFrequency(435000000), + range(0), + gain(0), + bias(0) +{ +} + +void FCDProInput::Settings::resetToDefaults() +{ + centerFrequency = 435000000; + range = 0; + gain = 0; + bias = 0; +} + +QByteArray FCDProInput::Settings::serialize() const +{ + FCDProSerializer::FCDData data; + + data.m_data.m_lnaGain = gain; + data.m_data.m_frequency = centerFrequency; + data.m_range = range; + data.m_bias = bias; + + QByteArray byteArray; + + FCDProSerializer::writeSerializedData(data, byteArray); + + return byteArray; + + /* + SimpleSerializer s(1); + s.writeU64(1, centerFrequency); + s.writeS32(2, range); + s.writeS32(3, gain); + s.writeS32(4, bias); + return s.final();*/ +} + +bool FCDProInput::Settings::deserialize(const QByteArray& serializedData) +{ + FCDProSerializer::FCDData data; + + bool valid = FCDProSerializer::readSerializedData(serializedData, data); + + gain = data.m_data.m_lnaGain; + centerFrequency = data.m_data.m_frequency; + range = data.m_range; + bias = data.m_bias; + + return valid; + + /* + SimpleDeserializer d(data); + + if (d.isValid() && d.getVersion() == 1) + { + d.readU64(1, ¢erFrequency, 435000000); + d.readS32(2, &range, 0); + d.readS32(3, &gain, 0); + d.readS32(4, &bias, 0); + return true; + } + + resetToDefaults(); + return true;*/ +} + +FCDProInput::FCDProInput() : + m_dev(0), + m_settings(), + m_FCDThread(0), + m_deviceDescription("Funcube Dongle Pro") +{ +} + +FCDProInput::~FCDProInput() +{ + stop(); +} + +bool FCDProInput::init(const Message& cmd) +{ + return false; +} + +bool FCDProInput::start(int device) +{ + qDebug() << "FCDProInput::start with device #" << device; + + QMutexLocker mutexLocker(&m_mutex); + + if (m_FCDThread) + { + return false; + } + + m_dev = fcdOpen(0x04D8, 0xFB56, device); + + if (m_dev == 0) + { + qCritical("FCDProInput::start: could not open FCD"); + return false; + } + + /* Apply settings before streaming to avoid bus contention; + * there is very little spare bandwidth on a full speed USB device. + * Failure is harmless if no device is found + * ... This is rubbish...*/ + + //applySettings(m_settings, true); + + if(!m_sampleFifo.setSize(96000*4)) + { + qCritical("Could not allocate SampleFifo"); + return false; + } + + if ((m_FCDThread = new FCDProThread(&m_sampleFifo)) == NULL) + { + qFatal("out of memory"); + return false; + } + + m_FCDThread->startWork(); + + mutexLocker.unlock(); + applySettings(m_settings, true); + + qDebug("FCDProInput::started"); + return true; +} + +void FCDProInput::stop() +{ + QMutexLocker mutexLocker(&m_mutex); + + if (m_FCDThread) + { + m_FCDThread->stopWork(); + // wait for thread to quit ? + delete m_FCDThread; + m_FCDThread = 0; + } + + fcdClose(m_dev); + m_dev = 0; +} + +const QString& FCDProInput::getDeviceDescription() const +{ + return m_deviceDescription; +} + +int FCDProInput::getSampleRate() const +{ + return 96000; +} + +quint64 FCDProInput::getCenterFrequency() const +{ + return m_settings.centerFrequency; +} + +bool FCDProInput::handleMessage(const Message& message) +{ + if(MsgConfigureFCD::match(message)) + { + qDebug() << "FCDProInput::handleMessage: MsgConfigureFCD"; + MsgConfigureFCD& conf = (MsgConfigureFCD&) message; + applySettings(conf.getSettings(), false); + return true; + } + else + { + return false; + } +} + +void FCDProInput::applySettings(const Settings& settings, bool force) +{ + bool signalChange = false; + + if ((m_settings.centerFrequency != settings.centerFrequency) || force) + { + qDebug() << "FCDProInput::applySettings: fc: " << settings.centerFrequency; + m_settings.centerFrequency = settings.centerFrequency; + + if (m_dev != 0) + { + set_center_freq((double) m_settings.centerFrequency); + } + + signalChange = true; + } + + if ((m_settings.gain != settings.gain) || force) + { + m_settings.gain = settings.gain; + + if (m_dev != 0) + { + set_lna_gain(settings.gain > 0); + } + } + + if ((m_settings.bias != settings.bias) || force) + { + m_settings.bias = settings.bias; + + if (m_dev != 0) + { + set_bias_t(settings.bias > 0); + } + } + + if (signalChange) + { + DSPSignalNotification *notif = new DSPSignalNotification(96000, m_settings.centerFrequency); + getOutputMessageQueue()->push(notif); + } +} + +void FCDProInput::set_center_freq(double freq) +{ + if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE) + { + qDebug("No FCD HID found for frquency change"); + } +} + +void FCDProInput::set_bias_t(bool on) +{ + quint8 cmd = on ? 1 : 0; + + fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1); +} + +void FCDProInput::set_lna_gain(bool on) +{ + quint8 cmd = on ? 1 : 0; + + fcdAppSetParam(m_dev, FCD_CMD_APP_SET_LNA_GAIN, &cmd, 1); +} + + diff --git a/plugins/samplesource/fcdpro/fcdproinput.h b/plugins/samplesource/fcdpro/fcdproinput.h new file mode 100644 index 000000000..def583db9 --- /dev/null +++ b/plugins/samplesource/fcdpro/fcdproinput.h @@ -0,0 +1,93 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FCDPROINPUT_H +#define INCLUDE_FCDPROINPUT_H + +#include "dsp/samplesource.h" +#include "fcdhid.h" +#include +#include + +struct fcd_buffer { + void *start; + std::size_t length; +}; + +class FCDProThread; + +class FCDProInput : public SampleSource { +public: + struct Settings { + Settings(); + quint64 centerFrequency; + qint32 range; + qint32 gain; + qint32 bias; + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + }; + + class MsgConfigureFCD : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const Settings& getSettings() const { return m_settings; } + + static MsgConfigureFCD* create(const Settings& settings) + { + return new MsgConfigureFCD(settings); + } + + private: + Settings m_settings; + + MsgConfigureFCD(const Settings& settings) : + Message(), + m_settings(settings) + { } + }; + + FCDProInput(); + virtual ~FCDProInput(); + + virtual bool init(const Message& cmd); + 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); + + void set_center_freq(double freq); + void set_bias_t(bool on); + void set_lna_gain(bool on); + +private: + void applySettings(const Settings& settings, bool force); + + hid_device *m_dev; + QMutex m_mutex; + Settings m_settings; + FCDProThread* m_FCDThread; + QString m_deviceDescription; +}; + +#endif // INCLUDE_FCDPROINPUT_H diff --git a/plugins/samplesource/fcdpro/fcdplugin.cpp b/plugins/samplesource/fcdpro/fcdproplugin.cpp similarity index 80% rename from plugins/samplesource/fcdpro/fcdplugin.cpp rename to plugins/samplesource/fcdpro/fcdproplugin.cpp index f6689d69c..30333c5ca 100644 --- a/plugins/samplesource/fcdpro/fcdplugin.cpp +++ b/plugins/samplesource/fcdpro/fcdproplugin.cpp @@ -18,10 +18,10 @@ #include #include "plugin/pluginapi.h" #include "util/simpleserializer.h" -#include "fcdplugin.h" -#include "fcdgui.h" +#include "fcdproplugin.h" +#include "fcdprogui.h" -const PluginDescriptor FCDPlugin::m_pluginDescriptor = { +const PluginDescriptor FCDProPlugin::m_pluginDescriptor = { QString("FunCube Pro Input"), QString("---"), QString("(c) Edouard Griffiths, F4EXB"), @@ -30,24 +30,24 @@ const PluginDescriptor FCDPlugin::m_pluginDescriptor = { QString("https://github.com/f4exb/sdrangel") }; -FCDPlugin::FCDPlugin(QObject* parent) : +FCDProPlugin::FCDProPlugin(QObject* parent) : QObject(parent) { } -const PluginDescriptor& FCDPlugin::getPluginDescriptor() const +const PluginDescriptor& FCDProPlugin::getPluginDescriptor() const { return m_pluginDescriptor; } -void FCDPlugin::initPlugin(PluginAPI* pluginAPI) +void FCDProPlugin::initPlugin(PluginAPI* pluginAPI) { m_pluginAPI = pluginAPI; m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcdpro", this); } -PluginInterface::SampleSourceDevices FCDPlugin::enumSampleSources() +PluginInterface::SampleSourceDevices FCDProPlugin::enumSampleSources() { SampleSourceDevices result; @@ -59,11 +59,11 @@ PluginInterface::SampleSourceDevices FCDPlugin::enumSampleSources() return result; } -PluginGUI* FCDPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address) +PluginGUI* FCDProPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address) { if(sourceName == "org.osmocom.sdr.samplesource.fcdpro") { - FCDGui* gui = new FCDGui(m_pluginAPI); + FCDProGui* gui = new FCDProGui(m_pluginAPI); m_pluginAPI->setInputGUI(gui); return gui; } diff --git a/plugins/samplesource/fcdpro/fcdplugin.h b/plugins/samplesource/fcdpro/fcdproplugin.h similarity index 75% rename from plugins/samplesource/fcdpro/fcdplugin.h rename to plugins/samplesource/fcdpro/fcdproplugin.h index f85a1fff5..b3a6c8284 100644 --- a/plugins/samplesource/fcdpro/fcdplugin.h +++ b/plugins/samplesource/fcdpro/fcdproplugin.h @@ -1,16 +1,16 @@ -#ifndef INCLUDE_FCDPLUGIN_H -#define INCLUDE_FCDPLUGIN_H +#ifndef INCLUDE_FCDPROPLUGIN_H +#define INCLUDE_FCDPROPLUGIN_H #include #include "plugin/plugininterface.h" -class FCDPlugin : public QObject, public PluginInterface { +class FCDProPlugin : public QObject, public PluginInterface { Q_OBJECT Q_INTERFACES(PluginInterface) Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcdpro") public: - explicit FCDPlugin(QObject* parent = NULL); + explicit FCDProPlugin(QObject* parent = NULL); const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); diff --git a/plugins/samplesource/fcdpro/fcdserializer.cpp b/plugins/samplesource/fcdpro/fcdproserializer.cpp similarity index 89% rename from plugins/samplesource/fcdpro/fcdserializer.cpp rename to plugins/samplesource/fcdpro/fcdproserializer.cpp index 68dd6d424..668cac4dc 100644 --- a/plugins/samplesource/fcdpro/fcdserializer.cpp +++ b/plugins/samplesource/fcdpro/fcdproserializer.cpp @@ -14,9 +14,9 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "fcdserializer.h" +#include "fcdproserializer.h" -void FCDSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData) +void FCDProSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData) { QByteArray sampleSourceSerialized; SampleSourceSerializer::writeSerializedData(data.m_data, sampleSourceSerialized); @@ -30,7 +30,7 @@ void FCDSerializer::writeSerializedData(const FCDData& data, QByteArray& seriali serializedData = s.final(); } -bool FCDSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data) +bool FCDProSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data) { bool valid = SampleSourceSerializer::readSerializedData(serializedData, data.m_data); @@ -61,7 +61,7 @@ bool FCDSerializer::readSerializedData(const QByteArray& serializedData, FCDData } } -void FCDSerializer::setDefaults(FCDData& data) +void FCDProSerializer::setDefaults(FCDData& data) { data.m_range = 0; data.m_bias = 0; diff --git a/plugins/samplesource/fcdpro/fcdserializer.h b/plugins/samplesource/fcdpro/fcdproserializer.h similarity index 89% rename from plugins/samplesource/fcdpro/fcdserializer.h rename to plugins/samplesource/fcdpro/fcdproserializer.h index 735dd6a56..2ec93931b 100644 --- a/plugins/samplesource/fcdpro/fcdserializer.h +++ b/plugins/samplesource/fcdpro/fcdproserializer.h @@ -14,12 +14,12 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ -#define PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ +#ifndef PLUGINS_SAMPLESOURCE_FCD_FCDPROSERIALIZER_H_ +#define PLUGINS_SAMPLESOURCE_FCD_FCDPROSERIALIZER_H_ #include "util/samplesourceserializer.h" -class FCDSerializer +class FCDProSerializer { public: struct FCDData @@ -36,4 +36,4 @@ public: -#endif /* PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ */ +#endif /* PLUGINS_SAMPLESOURCE_FCD_FCDPROSERIALIZER_H_ */ diff --git a/plugins/samplesource/fcdpro/fcdthread.cpp b/plugins/samplesource/fcdpro/fcdprothread.cpp similarity index 89% rename from plugins/samplesource/fcdpro/fcdthread.cpp rename to plugins/samplesource/fcdpro/fcdprothread.cpp index c59361b1c..cefc5ebec 100644 --- a/plugins/samplesource/fcdpro/fcdthread.cpp +++ b/plugins/samplesource/fcdpro/fcdprothread.cpp @@ -18,11 +18,11 @@ #include #include #include -#include "fcdthread.h" -#include "fcdinput.h" #include "dsp/samplefifo.h" +#include "fcdprothread.h" +#include "fcdproinput.h" -FCDThread::FCDThread(SampleFifo* sampleFifo, QObject* parent) : +FCDProThread::FCDProThread(SampleFifo* sampleFifo, QObject* parent) : QThread(parent), fcd_handle(NULL), m_running(false), @@ -32,11 +32,11 @@ FCDThread::FCDThread(SampleFifo* sampleFifo, QObject* parent) : start(); } -FCDThread::~FCDThread() +FCDProThread::~FCDProThread() { } -void FCDThread::startWork() +void FCDProThread::startWork() { m_startWaitMutex.lock(); @@ -50,15 +50,15 @@ void FCDThread::startWork() m_startWaitMutex.unlock(); } -void FCDThread::stopWork() +void FCDProThread::stopWork() { m_running = false; wait(); } -void FCDThread::run() +void FCDProThread::run() { - if ( !OpenSource("hw:CARD=V20") ) + if ( !OpenSource("hw:CARD=V10") ) { qCritical() << "FCDThread::run: cannot open FCD sound card"; return; @@ -78,7 +78,7 @@ void FCDThread::run() CloseSource(); } -bool FCDThread::OpenSource(const char* cardname) +bool FCDProThread::OpenSource(const char* cardname) { bool fail = false; snd_pcm_hw_params_t* params; @@ -133,7 +133,7 @@ bool FCDThread::OpenSource(const char* cardname) return true; } -void FCDThread::CloseSource() +void FCDProThread::CloseSource() { if (fcd_handle) { @@ -143,7 +143,7 @@ void FCDThread::CloseSource() fcd_handle = NULL; } -int FCDThread::work(int n_items) +int FCDProThread::work(int n_items) { int l; SampleVector::iterator it; diff --git a/plugins/samplesource/fcdpro/fcdprothread.h b/plugins/samplesource/fcdpro/fcdprothread.h new file mode 100644 index 000000000..6771701c2 --- /dev/null +++ b/plugins/samplesource/fcdpro/fcdprothread.h @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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_FCDPROTHREAD_H +#define INCLUDE_FCDPROTHREAD_H + +#include +#include +#include +#include "dsp/samplefifo.h" +#include "dsp/inthalfbandfilter.h" +#include + +#define FCDPP_RATE 192000 +#define FCD_BLOCKSIZE (1<<11) + +class FCDProThread : public QThread { + Q_OBJECT + +public: + FCDProThread(SampleFifo* sampleFifo, QObject* parent = NULL); + ~FCDProThread(); + + void startWork(); + void stopWork(); + bool OpenSource(const char *filename); + void CloseSource(); + +private: + snd_pcm_t* fcd_handle; + + QMutex m_startWaitMutex; + QWaitCondition m_startWaiter; + bool m_running; + + SampleVector m_convertBuffer; + SampleFifo* m_sampleFifo; + + void run(); + int work(int n_items); +}; +#endif // INCLUDE_FCDPROTHREAD_H diff --git a/plugins/samplesource/fcdproplus/CMakeLists.txt b/plugins/samplesource/fcdproplus/CMakeLists.txt new file mode 100644 index 000000000..1bd5d9a12 --- /dev/null +++ b/plugins/samplesource/fcdproplus/CMakeLists.txt @@ -0,0 +1,53 @@ +project(fcdproplus) + +set(fcdproplus_SOURCES + fcdproplusgui.cpp + fcdproplusinput.cpp + fcdproplusplugin.cpp + fcdproplusserializer.cpp + fcdproplusthread.cpp +) + +set(fcdproplus_HEADERS + fcdproplusgui.h + fcdproplusinput.h + fcdproplusplugin.h + fcdproplusserializer.h + fcdproplusthread.h +) + +set(fcdproplus_FORMS + fcdproplusgui.ui +) + +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/include-gpl + ${CMAKE_SOURCE_DIR}/fcdhid +) + +#include(${QT_USE_FILE}) +add_definitions(${QT_DEFINITIONS}) +add_definitions(-DQT_PLUGIN) +add_definitions(-DQT_SHARED) + +#qt4_wrap_cpp(fcdproplus_HEADERS_MOC ${fcdproplus_HEADERS}) +qt5_wrap_ui(fcdproplus_FORMS_HEADERS ${fcdproplus_FORMS}) + +add_library(inputfcdproplus SHARED + ${fcdproplus_SOURCES} + ${fcdproplus_HEADERS_MOC} + ${fcdproplus_FORMS_HEADERS} +) + +target_link_libraries(inputfcdproplus + ${QT_LIBRARIES} + ${LIBUSB_LIBRARIES} + asound + fcdhid + sdrbase +) + +qt5_use_modules(inputfcdproplus Core Widgets OpenGL Multimedia) diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp new file mode 100644 index 000000000..c6519cd1a --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp @@ -0,0 +1,154 @@ +#include "ui_fcdproplusgui.h" +#include "plugin/pluginapi.h" +#include "gui/colormapper.h" +#include "dsp/dspengine.h" +#include "fcdproplusgui.h" + +FCDProPlusGui::FCDProPlusGui(PluginAPI* pluginAPI, QWidget* parent) : + QWidget(parent), + ui(new Ui::FCDProPlusGui), + m_pluginAPI(pluginAPI), + m_settings(), + m_sampleSource(NULL) +{ + ui->setupUi(this); + ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); + ui->centerFrequency->setValueRange(7, 64000U, 1700000U); + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); + displaySettings(); + + m_sampleSource = new FCDProPlusInput(); + DSPEngine::instance()->setSource(m_sampleSource); +} + +FCDProPlusGui::~FCDProPlusGui() +{ + delete ui; +} + +void FCDProPlusGui::destroy() +{ + delete this; +} + +void FCDProPlusGui::setName(const QString& name) +{ + setObjectName(name); +} + +QString FCDProPlusGui::getName() const +{ + return objectName(); +} + +void FCDProPlusGui::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + sendSettings(); +} + +qint64 FCDProPlusGui::getCenterFrequency() const +{ + return m_settings.centerFrequency; +} + +QByteArray FCDProPlusGui::serialize() const +{ + return m_settings.serialize(); +} + +bool FCDProPlusGui::deserialize(const QByteArray& data) +{ + if(m_settings.deserialize(data)) + { + displaySettings(); + sendSettings(); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool FCDProPlusGui::handleMessage(const Message& message) +{ + return false; +} + +void FCDProPlusGui::displaySettings() +{ + ui->centerFrequency->setValue(m_settings.centerFrequency / 1000); + ui->checkBoxR->setChecked(m_settings.range); + ui->checkBoxG->setChecked(m_settings.gain); + ui->checkBoxB->setChecked(m_settings.bias); +} + +void FCDProPlusGui::sendSettings() +{ + if(!m_updateTimer.isActive()) + m_updateTimer.start(100); +} + +void FCDProPlusGui::on_centerFrequency_changed(quint64 value) +{ + m_settings.centerFrequency = value * 1000; + sendSettings(); +} + +void FCDProPlusGui::updateHardware() +{ + FCDProPlusInput::MsgConfigureFCD* message = FCDProPlusInput::MsgConfigureFCD::create(m_settings); + m_sampleSource->getInputMessageQueue()->push(message); + m_updateTimer.stop(); +} + +void FCDProPlusGui::on_checkBoxR_stateChanged(int state) +{ + if (state == Qt::Checked) // FIXME: this is for the Pro+ version only! + { + ui->centerFrequency->setValueRange(7, 150U, 240000U); + ui->centerFrequency->setValue(7000); + m_settings.centerFrequency = 7000 * 1000; + m_settings.range = 1; + } + else + { + ui->centerFrequency->setValueRange(7, 64000U, 1900000U); + ui->centerFrequency->setValue(435000); + m_settings.centerFrequency = 435000 * 1000; + m_settings.range = 0; + } + + sendSettings(); +} + +void FCDProPlusGui::on_checkBoxG_stateChanged(int state) +{ + if (state == Qt::Checked) + { + m_settings.gain = 1; + } + else + { + m_settings.gain = 0; + } + + sendSettings(); +} + +void FCDProPlusGui::on_checkBoxB_stateChanged(int state) +{ + if (state == Qt::Checked) + { + m_settings.bias = 1; + } + else + { + m_settings.bias = 0; + } + + sendSettings(); +} diff --git a/plugins/samplesource/fcdpro/fcdgui.h b/plugins/samplesource/fcdproplus/fcdproplusgui.h similarity index 75% rename from plugins/samplesource/fcdpro/fcdgui.h rename to plugins/samplesource/fcdproplus/fcdproplusgui.h index fc0ba3517..cb8896008 100644 --- a/plugins/samplesource/fcdpro/fcdgui.h +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.h @@ -2,21 +2,22 @@ #define INCLUDE_FCDGUI_H #include + +#include "fcdproplusinput.h" #include "plugin/plugingui.h" -#include "fcdinput.h" class PluginAPI; namespace Ui { - class FCDGui; + class FCDProPlusGui; } -class FCDGui : public QWidget, public PluginGUI { +class FCDProPlusGui : public QWidget, public PluginGUI { Q_OBJECT public: - explicit FCDGui(PluginAPI* pluginAPI, QWidget* parent = NULL); - virtual ~FCDGui(); + explicit FCDProPlusGui(PluginAPI* pluginAPI, QWidget* parent = NULL); + virtual ~FCDProPlusGui(); void destroy(); void setName(const QString& name); @@ -30,10 +31,10 @@ public: virtual bool handleMessage(const Message& message); private: - Ui::FCDGui* ui; + Ui::FCDProPlusGui* ui; PluginAPI* m_pluginAPI; - FCDInput::Settings m_settings; + FCDProPlusInput::Settings m_settings; QTimer m_updateTimer; std::vector m_gains; SampleSource* m_sampleSource; diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.ui b/plugins/samplesource/fcdproplus/fcdproplusgui.ui new file mode 100644 index 000000000..5526d38c7 --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.ui @@ -0,0 +1,144 @@ + + + FCDProPlusGui + + + + 0 + 0 + 165 + 119 + + + + + 0 + 0 + + + + FunCubeDongle + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Monospace + 20 + + + + Qt::StrongFocus + + + Tuner center frequency in kHz + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + + + + + + Low Range + + + + + + + + + + + LNA Gain + + + + + + + Bias T + + + + + + + + + + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
+
+ + +
diff --git a/plugins/samplesource/fcdpro/fcdinput.cpp b/plugins/samplesource/fcdproplus/fcdproplusinput.cpp similarity index 75% rename from plugins/samplesource/fcdpro/fcdinput.cpp rename to plugins/samplesource/fcdproplus/fcdproplusinput.cpp index 3035c2a87..976d2943e 100644 --- a/plugins/samplesource/fcdpro/fcdinput.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusinput.cpp @@ -20,13 +20,14 @@ #include #include #include -#include "fcdinput.h" -#include "fcdthread.h" -#include "fcdgui.h" #include "dsp/dspcommands.h" -#include "fcdserializer.h" +#include "fcdproplusinput.h" -MESSAGE_CLASS_DEFINITION(FCDInput::MsgConfigureFCD, Message) +#include "fcdproplusgui.h" +#include "fcdproplusserializer.h" +#include "fcdproplusthread.h" + +MESSAGE_CLASS_DEFINITION(FCDProPlusInput::MsgConfigureFCD, Message) //MESSAGE_CLASS_DEFINITION(FCDInput::MsgReportFCD, Message) /* @@ -40,7 +41,7 @@ const int FCDInput::m_sampleRate = 96000; const std::string FCDInput::m_deviceName("hw:CARD=V10"); */ -FCDInput::Settings::Settings() : +FCDProPlusInput::Settings::Settings() : centerFrequency(435000000), range(0), gain(0), @@ -48,7 +49,7 @@ FCDInput::Settings::Settings() : { } -void FCDInput::Settings::resetToDefaults() +void FCDProPlusInput::Settings::resetToDefaults() { centerFrequency = 435000000; range = 0; @@ -56,9 +57,9 @@ void FCDInput::Settings::resetToDefaults() bias = 0; } -QByteArray FCDInput::Settings::serialize() const +QByteArray FCDProPlusInput::Settings::serialize() const { - FCDSerializer::FCDData data; + FCDProPlusSerializer::FCDData data; data.m_data.m_lnaGain = gain; data.m_data.m_frequency = centerFrequency; @@ -67,7 +68,7 @@ QByteArray FCDInput::Settings::serialize() const QByteArray byteArray; - FCDSerializer::writeSerializedData(data, byteArray); + FCDProPlusSerializer::writeSerializedData(data, byteArray); return byteArray; @@ -80,11 +81,11 @@ QByteArray FCDInput::Settings::serialize() const return s.final();*/ } -bool FCDInput::Settings::deserialize(const QByteArray& serializedData) +bool FCDProPlusInput::Settings::deserialize(const QByteArray& serializedData) { - FCDSerializer::FCDData data; + FCDProPlusSerializer::FCDData data; - bool valid = FCDSerializer::readSerializedData(serializedData, data); + bool valid = FCDProPlusSerializer::readSerializedData(serializedData, data); gain = data.m_data.m_lnaGain; centerFrequency = data.m_data.m_frequency; @@ -109,27 +110,27 @@ bool FCDInput::Settings::deserialize(const QByteArray& serializedData) return true;*/ } -FCDInput::FCDInput() : +FCDProPlusInput::FCDProPlusInput() : m_dev(0), m_settings(), m_FCDThread(0), - m_deviceDescription() + m_deviceDescription("Funcube Dongle Pro+") { } -FCDInput::~FCDInput() +FCDProPlusInput::~FCDProPlusInput() { stop(); } -bool FCDInput::init(const Message& cmd) +bool FCDProPlusInput::init(const Message& cmd) { return false; } -bool FCDInput::start(int device) +bool FCDProPlusInput::start(int device) { - qDebug() << "FCDInput::start with device #" << device; + qDebug() << "FCDProPlusInput::start with device #" << device; QMutexLocker mutexLocker(&m_mutex); @@ -142,12 +143,10 @@ bool FCDInput::start(int device) if (m_dev == 0) { - qCritical("FCDInput::start: could not open FCD"); + qCritical("FCDProPlusInput::start: could not open FCD"); return false; } - m_deviceDescription = QString("Funcube Dongle"); - /* Apply settings before streaming to avoid bus contention; * there is very little spare bandwidth on a full speed USB device. * Failure is harmless if no device is found @@ -161,7 +160,7 @@ bool FCDInput::start(int device) return false; } - if ((m_FCDThread = new FCDThread(&m_sampleFifo)) == NULL) + if ((m_FCDThread = new FCDProPlusThread(&m_sampleFifo)) == NULL) { qFatal("out of memory"); return false; @@ -172,11 +171,11 @@ bool FCDInput::start(int device) mutexLocker.unlock(); applySettings(m_settings, true); - qDebug("FCDInput::started"); + qDebug("FCDProPlusInput::started"); return true; } -void FCDInput::stop() +void FCDProPlusInput::stop() { QMutexLocker mutexLocker(&m_mutex); @@ -190,30 +189,28 @@ void FCDInput::stop() fcdClose(m_dev); m_dev = 0; - - m_deviceDescription.clear(); } -const QString& FCDInput::getDeviceDescription() const +const QString& FCDProPlusInput::getDeviceDescription() const { return m_deviceDescription; } -int FCDInput::getSampleRate() const +int FCDProPlusInput::getSampleRate() const { return 192000; } -quint64 FCDInput::getCenterFrequency() const +quint64 FCDProPlusInput::getCenterFrequency() const { return m_settings.centerFrequency; } -bool FCDInput::handleMessage(const Message& message) +bool FCDProPlusInput::handleMessage(const Message& message) { if(MsgConfigureFCD::match(message)) { - qDebug() << "FCDInput::handleMessage: MsgConfigureFCD"; + qDebug() << "FCDProPlusInput::handleMessage: MsgConfigureFCD"; MsgConfigureFCD& conf = (MsgConfigureFCD&) message; applySettings(conf.getSettings(), false); return true; @@ -224,13 +221,13 @@ bool FCDInput::handleMessage(const Message& message) } } -void FCDInput::applySettings(const Settings& settings, bool force) +void FCDProPlusInput::applySettings(const Settings& settings, bool force) { bool signalChange = false; if ((m_settings.centerFrequency != settings.centerFrequency) || force) { - qDebug() << "FCDInput::applySettings: fc: " << settings.centerFrequency; + qDebug() << "FCDProPlusInput::applySettings: fc: " << settings.centerFrequency; m_settings.centerFrequency = settings.centerFrequency; if (m_dev != 0) @@ -268,7 +265,7 @@ void FCDInput::applySettings(const Settings& settings, bool force) } } -void FCDInput::set_center_freq(double freq) +void FCDProPlusInput::set_center_freq(double freq) { if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE) { @@ -276,14 +273,14 @@ void FCDInput::set_center_freq(double freq) } } -void FCDInput::set_bias_t(bool on) +void FCDProPlusInput::set_bias_t(bool on) { quint8 cmd = on ? 1 : 0; fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1); } -void FCDInput::set_lna_gain(bool on) +void FCDProPlusInput::set_lna_gain(bool on) { quint8 cmd = on ? 1 : 0; diff --git a/plugins/samplesource/fcdpro/fcdinput.h b/plugins/samplesource/fcdproplus/fcdproplusinput.h similarity index 94% rename from plugins/samplesource/fcdpro/fcdinput.h rename to plugins/samplesource/fcdproplus/fcdproplusinput.h index ddaf7d7ef..9479cb319 100644 --- a/plugins/samplesource/fcdpro/fcdinput.h +++ b/plugins/samplesource/fcdproplus/fcdproplusinput.h @@ -28,9 +28,9 @@ struct fcd_buffer { std::size_t length; }; -class FCDThread; +class FCDProPlusThread; -class FCDInput : public SampleSource { +class FCDProPlusInput : public SampleSource { public: struct Settings { Settings(); @@ -63,8 +63,8 @@ public: { } }; - FCDInput(); - virtual ~FCDInput(); + FCDProPlusInput(); + virtual ~FCDProPlusInput(); virtual bool init(const Message& cmd); virtual bool start(int device); @@ -86,7 +86,7 @@ private: hid_device *m_dev; QMutex m_mutex; Settings m_settings; - FCDThread* m_FCDThread; + FCDProPlusThread* m_FCDThread; QString m_deviceDescription; }; diff --git a/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp b/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp new file mode 100644 index 000000000..4f7c53a9a --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "fcdproplusplugin.h" +#include "fcdproplusgui.h" + +const PluginDescriptor FCDProPlusPlugin::m_pluginDescriptor = { + QString("FunCube Pro+ Input"), + QString("---"), + QString("(c) Edouard Griffiths, F4EXB"), + QString("https://github.com/f4exb/sdrangel"), + true, + QString("https://github.com/f4exb/sdrangel") +}; + +FCDProPlusPlugin::FCDProPlusPlugin(QObject* parent) : + QObject(parent) +{ +} + +const PluginDescriptor& FCDProPlusPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void FCDProPlusPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcdproplus", this); +} + +PluginInterface::SampleSourceDevices FCDProPlusPlugin::enumSampleSources() +{ + SampleSourceDevices result; + + QString displayedName(QString("FunCube Pro+ #1")); + SimpleSerializer s(1); + s.writeS32(1, 0); + result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.fcdproplus", s.final())); + + return result; +} + +PluginGUI* FCDProPlusPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address) +{ + if(sourceName == "org.osmocom.sdr.samplesource.fcdproplus") + { + FCDProPlusGui* gui = new FCDProPlusGui(m_pluginAPI); + m_pluginAPI->setInputGUI(gui); + return gui; + } + else + { + return NULL; + } +} diff --git a/plugins/samplesource/fcdproplus/fcdproplusplugin.h b/plugins/samplesource/fcdproplus/fcdproplusplugin.h new file mode 100644 index 000000000..448b8cfd2 --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusplugin.h @@ -0,0 +1,27 @@ +#ifndef INCLUDE_FCDPROPLUSPLUGIN_H +#define INCLUDE_FCDPROPLUSPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class FCDProPlusPlugin : public QObject, public PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcdproplus") + +public: + explicit FCDProPlusPlugin(QObject* parent = NULL); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + SampleSourceDevices enumSampleSources(); + PluginGUI* createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address); + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_FCDPROPLUSPLUGIN_H diff --git a/plugins/samplesource/fcdproplus/fcdproplusserializer.cpp b/plugins/samplesource/fcdproplus/fcdproplusserializer.cpp new file mode 100644 index 000000000..b4151727c --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusserializer.cpp @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "fcdproplusserializer.h" + +void FCDProPlusSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData) +{ + QByteArray sampleSourceSerialized; + SampleSourceSerializer::writeSerializedData(data.m_data, sampleSourceSerialized); + + SimpleSerializer s(1); + + s.writeBlob(1, sampleSourceSerialized); + s.writeS32(2, data.m_bias); + s.writeS32(3, data.m_range); + + serializedData = s.final(); +} + +bool FCDProPlusSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data) +{ + bool valid = SampleSourceSerializer::readSerializedData(serializedData, data.m_data); + + QByteArray sampleSourceSerialized; + + SimpleDeserializer d(serializedData); + + if (!d.isValid()) + { + setDefaults(data); + return false; + } + + if (d.getVersion() == SampleSourceSerializer::getSerializerVersion()) + { + int intval; + + d.readBlob(1, &sampleSourceSerialized); + d.readS32(2, &data.m_bias); + d.readS32(3, &data.m_range); + + return SampleSourceSerializer::readSerializedData(sampleSourceSerialized, data.m_data); + } + else + { + setDefaults(data); + return false; + } +} + +void FCDProPlusSerializer::setDefaults(FCDData& data) +{ + data.m_range = 0; + data.m_bias = 0; +} diff --git a/plugins/samplesource/fcdproplus/fcdproplusserializer.h b/plugins/samplesource/fcdproplus/fcdproplusserializer.h new file mode 100644 index 000000000..ffd7f2b02 --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusserializer.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 PLUGINS_SAMPLESOURCE_FCD_FCDPROPLUSSERIALIZER_H_ +#define PLUGINS_SAMPLESOURCE_FCD_FCDPROPLUSSERIALIZER_H_ + +#include "util/samplesourceserializer.h" + +class FCDProPlusSerializer +{ +public: + struct FCDData + { + SampleSourceSerializer::Data m_data; + qint32 m_bias; + qint32 m_range; + }; + + static void writeSerializedData(const FCDData& data, QByteArray& serializedData); + static bool readSerializedData(const QByteArray& serializedData, FCDData& data); + static void setDefaults(FCDData& data); +}; + + + +#endif /* PLUGINS_SAMPLESOURCE_FCD_FCDPROPLUSSERIALIZER_H_ */ diff --git a/plugins/samplesource/fcdproplus/fcdproplusthread.cpp b/plugins/samplesource/fcdproplus/fcdproplusthread.cpp new file mode 100644 index 000000000..e57ed41a6 --- /dev/null +++ b/plugins/samplesource/fcdproplus/fcdproplusthread.cpp @@ -0,0 +1,164 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "dsp/samplefifo.h" +#include "fcdproplusthread.h" +#include "fcdproplusinput.h" + +FCDProPlusThread::FCDProPlusThread(SampleFifo* sampleFifo, QObject* parent) : + QThread(parent), + fcd_handle(NULL), + m_running(false), + m_convertBuffer(FCD_BLOCKSIZE), + m_sampleFifo(sampleFifo) +{ + start(); +} + +FCDProPlusThread::~FCDProPlusThread() +{ +} + +void FCDProPlusThread::startWork() +{ + m_startWaitMutex.lock(); + + start(); + + while(!m_running) + { + m_startWaiter.wait(&m_startWaitMutex, 100); + } + + m_startWaitMutex.unlock(); +} + +void FCDProPlusThread::stopWork() +{ + m_running = false; + wait(); +} + +void FCDProPlusThread::run() +{ + if ( !OpenSource("hw:CARD=V20") ) + { + qCritical() << "FCDThread::run: cannot open FCD sound card"; + return; + } + // TODO: fallback to original fcd + + m_running = true; + + while(m_running) + { + if (work(FCD_BLOCKSIZE) < 0) + { + break; + } + } + + CloseSource(); +} + +bool FCDProPlusThread::OpenSource(const char* cardname) +{ + bool fail = false; + snd_pcm_hw_params_t* params; + //fcd_rate = FCDPP_RATE; + //fcd_channels =2; + //fcd_format = SND_PCM_SFMT_U16_LE; + snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE; + + if (fcd_handle) + { + return false; + } + + if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0) + { + qCritical("FCDThread::OpenSource: cannot open %s", cardname); + return false; + } + + snd_pcm_hw_params_alloca(¶ms); + + if (snd_pcm_hw_params_any(fcd_handle, params) < 0) + { + qCritical("FCDProPlusThread::OpenSource: snd_pcm_hw_params_any failed"); + fail = true; + } + else if (snd_pcm_hw_params(fcd_handle, params) < 0) + { + qCritical("FCDProPlusThread::OpenSource: snd_pcm_hw_params failed"); + fail = true; + // TODO: check actual samplerate, may be crippled firmware + } + else + { + if (snd_pcm_start(fcd_handle) < 0) + { + qCritical("FCDProPlusThread::OpenSource: snd_pcm_start failed"); + fail = true; + } + } + + if (fail) + { + snd_pcm_close( fcd_handle ); + return false; + } + else + { + qDebug("FCDProPlusThread::OpenSource: Funcube stream started"); + } + + return true; +} + +void FCDProPlusThread::CloseSource() +{ + if (fcd_handle) + { + snd_pcm_close( fcd_handle ); + } + + fcd_handle = NULL; +} + +int FCDProPlusThread::work(int n_items) +{ + int l; + SampleVector::iterator it; + void *out; + + it = m_convertBuffer.begin(); + out = (void *)&it[0]; + l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items); + if (l > 0) + m_sampleFifo->write(it, it + l); + if (l == -EPIPE) { + qDebug("FCDProPlusThread::work: Overrun detected"); + return 0; + } + return l; +} + + diff --git a/plugins/samplesource/fcdpro/fcdthread.h b/plugins/samplesource/fcdproplus/fcdproplusthread.h similarity index 90% rename from plugins/samplesource/fcdpro/fcdthread.h rename to plugins/samplesource/fcdproplus/fcdproplusthread.h index 76156a1b4..7e740e70c 100644 --- a/plugins/samplesource/fcdpro/fcdthread.h +++ b/plugins/samplesource/fcdproplus/fcdproplusthread.h @@ -25,15 +25,15 @@ #include "dsp/inthalfbandfilter.h" #include -#define FCDPP_RATE 192000 // FIXME: The Pro / Pro+ switch should be handled better than this! +#define FCDPP_RATE 192000 #define FCD_BLOCKSIZE (1<<11) -class FCDThread : public QThread { +class FCDProPlusThread : public QThread { Q_OBJECT public: - FCDThread(SampleFifo* sampleFifo, QObject* parent = NULL); - ~FCDThread(); + FCDProPlusThread(SampleFifo* sampleFifo, QObject* parent = NULL); + ~FCDProPlusThread(); void startWork(); void stopWork();