From beda4892610f8b79c41a9458704f2d7656fee3ed Mon Sep 17 00:00:00 2001 From: John Greb Date: Sat, 29 Nov 2014 18:09:35 +0000 Subject: [PATCH] FCD template. --- plugins/samplesource/CMakeLists.txt | 4 + plugins/samplesource/fcd/CMakeLists.txt | 49 +++++ plugins/samplesource/fcd/fcdgui.cpp | 137 +++++++++++++ plugins/samplesource/fcd/fcdgui.h | 53 +++++ plugins/samplesource/fcd/fcdgui.ui | 260 ++++++++++++++++++++++++ plugins/samplesource/fcd/fcdinput.cpp | 135 ++++++++++++ plugins/samplesource/fcd/fcdinput.h | 83 ++++++++ plugins/samplesource/fcd/fcdplugin.cpp | 55 +++++ plugins/samplesource/fcd/fcdplugin.h | 27 +++ plugins/samplesource/fcd/fcdsource.cpp | 0 plugins/samplesource/fcd/fcdthread.cpp | 54 +++++ plugins/samplesource/fcd/fcdthread.h | 60 ++++++ 12 files changed, 917 insertions(+) create mode 100644 plugins/samplesource/fcd/CMakeLists.txt create mode 100644 plugins/samplesource/fcd/fcdgui.cpp create mode 100644 plugins/samplesource/fcd/fcdgui.h create mode 100644 plugins/samplesource/fcd/fcdgui.ui create mode 100644 plugins/samplesource/fcd/fcdinput.cpp create mode 100644 plugins/samplesource/fcd/fcdinput.h create mode 100644 plugins/samplesource/fcd/fcdplugin.cpp create mode 100644 plugins/samplesource/fcd/fcdplugin.h create mode 100644 plugins/samplesource/fcd/fcdsource.cpp create mode 100644 plugins/samplesource/fcd/fcdthread.cpp create mode 100644 plugins/samplesource/fcd/fcdthread.h diff --git a/plugins/samplesource/CMakeLists.txt b/plugins/samplesource/CMakeLists.txt index a27242b3a..b12ef2de7 100644 --- a/plugins/samplesource/CMakeLists.txt +++ b/plugins/samplesource/CMakeLists.txt @@ -17,6 +17,10 @@ else() find_package(LibRTLSDR) endif() +if(LIBUSB_FOUND AND UNIX) + add_subdirectory(fcd) +endif() + if(LIBUSB_FOUND AND LIBRTLSDR_FOUND) add_subdirectory(rtlsdr) endif(LIBUSB_FOUND AND LIBRTLSDR_FOUND) diff --git a/plugins/samplesource/fcd/CMakeLists.txt b/plugins/samplesource/fcd/CMakeLists.txt new file mode 100644 index 000000000..14807c754 --- /dev/null +++ b/plugins/samplesource/fcd/CMakeLists.txt @@ -0,0 +1,49 @@ +project(fcd) + +set(fcd_SOURCES + fcdgui.cpp + fcdinput.cpp + fcdplugin.cpp + fcdthread.cpp + fcdsource.cpp +) + +set(rtlsdr_HEADERS + fcdgui.h + fcdinput.h + fcdplugin.h + fcdthread.h + fcdsource.h +) + +set(fcd_FORMS + fcdgui.ui +) + +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/include-gpl +) + +#include(${QT_USE_FILE}) +add_definitions(${QT_DEFINITIONS}) +add_definitions(-DQT_PLUGIN) +add_definitions(-DQT_SHARED) + +#qt4_wrap_cpp(fcd_HEADERS_MOC ${fcd_HEADERS}) +qt5_wrap_ui(fcd_FORMS_HEADERS ${fcd_FORMS}) + +add_library(inputfcd SHARED + ${fcd_SOURCES} + ${fcd_HEADERS_MOC} + ${fcd_FORMS_HEADERS} +) + +target_link_libraries(inputfcd + ${QT_LIBRARIES} + sdrbase +) + +qt5_use_modules(inputfcd Core Widgets OpenGL Multimedia) diff --git a/plugins/samplesource/fcd/fcdgui.cpp b/plugins/samplesource/fcd/fcdgui.cpp new file mode 100644 index 000000000..01249cb83 --- /dev/null +++ b/plugins/samplesource/fcd/fcdgui.cpp @@ -0,0 +1,137 @@ +#include "fcdgui.h" +#include "ui_fcdgui.h" +#include "plugin/pluginapi.h" + +FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) : + QWidget(parent), + ui(new Ui::FCDGui), + m_pluginAPI(pluginAPI), + m_settings(), + m_sampleSource(NULL) +{ + ui->setupUi(this); + ui->centerFrequency->setValueRange(7, 420000U, 1900000U); + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); + displaySettings(); + + m_sampleSource = new FCDInput(m_pluginAPI->getMainWindowMessageQueue()); + m_pluginAPI->setSampleSource(m_sampleSource); +} + +FCDGui::~FCDGui() +{ + delete ui; +} + +void FCDGui::destroy() +{ + delete this; +} + +void FCDGui::setName(const QString& name) +{ + setObjectName(name); +} + +void FCDGui::resetToDefaults() +{ + m_generalSettings.resetToDefaults(); + m_settings.resetToDefaults(); + displaySettings(); + sendSettings(); +} + +QByteArray FCDGui::serializeGeneral() const +{ + return m_generalSettings.serialize(); +} + +bool FCDGui::deserializeGeneral(const QByteArray&data) +{ + if(m_generalSettings.deserialize(data)) { + displaySettings(); + sendSettings(); + return true; + } else { + resetToDefaults(); + return false; + } +} + +quint64 FCDGui::getCenterFrequency() const +{ + return m_generalSettings.m_centerFrequency; +} + +QByteArray FCDGui::serialize() const +{ + return m_settings.serialize(); +} + +bool FCDGui::deserialize(const QByteArray& data) +{ + if(m_settings.deserialize(data)) { + displaySettings(); + sendSettings(); + return true; + } else { + resetToDefaults(); + return false; + } +} + +bool FCDGui::handleMessage(Message* message) +{ + return true; +} + +void FCDGui::displaySettings() +{ + ui->centerFrequency->setValue(m_generalSettings.m_centerFrequency / 1000); +} + +void FCDGui::sendSettings() +{ + if(!m_updateTimer.isActive()) + m_updateTimer.start(100); +} + +void FCDGui::on_centerFrequency_changed(quint64 value) +{ + m_generalSettings.m_centerFrequency = value * 1000; + sendSettings(); +} + +#if 0 +void FCDGui::on_gain_valueChanged(int value) +{ + if(value > (int)m_gains.size()) + return; + int gain = m_gains[value]; + ui->gainText->setText(tr("%1.%2").arg(gain / 10).arg(abs(gain % 10))); + m_settings.m_gain = gain; + sendSettings(); +} +#endif + +void FCDGui::updateHardware() +{ + FCDInput::MsgConfigureFCD* message = FCDInput::MsgConfigureFCD::create(m_generalSettings, m_settings); + message->submit(m_pluginAPI->getDSPEngineMessageQueue()); + m_updateTimer.stop(); +} + +void FCDGui::on_checkBox_stateChanged(int state) { + if (state == Qt::Checked){ + ui->centerFrequency->setValueRange(7, 150U, 240000U); + ui->centerFrequency->setValue(7000); + m_generalSettings.m_centerFrequency = 7000 * 1000; + } + else { + ui->centerFrequency->setValueRange(7, 420000U, 1900000U); + ui->centerFrequency->setValue(434450); + m_generalSettings.m_centerFrequency = 434450 * 1000; + } + sendSettings(); +} + diff --git a/plugins/samplesource/fcd/fcdgui.h b/plugins/samplesource/fcd/fcdgui.h new file mode 100644 index 000000000..880e164f6 --- /dev/null +++ b/plugins/samplesource/fcd/fcdgui.h @@ -0,0 +1,53 @@ +#ifndef INCLUDE_FCDGUI_H +#define INCLUDE_FCDGUI_H + +#include +#include "plugin/plugingui.h" +#include "fcdinput.h" + +class PluginAPI; + +namespace Ui { + class FCDGui; +} + +class FCDGui : public QWidget, public PluginGUI { + Q_OBJECT + +public: + explicit FCDGui(PluginAPI* pluginAPI, QWidget* parent = NULL); + ~FCDGui(); + void destroy(); + + void setName(const QString& name); + + void resetToDefaults(); + QByteArray serializeGeneral() const; + bool deserializeGeneral(const QByteArray&data); + quint64 getCenterFrequency() const; + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + bool handleMessage(Message* message); + +private: + Ui::FCDGui* ui; + + PluginAPI* m_pluginAPI; + SampleSource::GeneralSettings m_generalSettings; + FCDInput::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_gain_valueChanged(int value); + //void on_samplerate_valueChanged(int value); + void on_checkBox_stateChanged(int state); + void updateHardware(); +}; + +#endif // INCLUDE_FCDGUI_H diff --git a/plugins/samplesource/fcd/fcdgui.ui b/plugins/samplesource/fcd/fcdgui.ui new file mode 100644 index 000000000..99fc0190d --- /dev/null +++ b/plugins/samplesource/fcd/fcdgui.ui @@ -0,0 +1,260 @@ + + + FCDGui + + + + 0 + 0 + 132 + 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 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
+
+ + +
diff --git a/plugins/samplesource/fcd/fcdinput.cpp b/plugins/samplesource/fcd/fcdinput.cpp new file mode 100644 index 000000000..2555233b5 --- /dev/null +++ b/plugins/samplesource/fcd/fcdinput.cpp @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "fcdinput.h" +#include "fcdthread.h" +#include "fcdgui.h" +#include "util/simpleserializer.h" + +MESSAGE_CLASS_DEFINITION(FCDInput::MsgConfigureFCD, Message) +//MESSAGE_CLASS_DEFINITION(FCDInput::MsgReportFCD, Message) + +FCDInput::Settings::Settings() +{ +} + +void FCDInput::Settings::resetToDefaults() +{ +} + +QByteArray FCDInput::Settings::serialize() const +{ + SimpleSerializer s(1); + return s.final(); +} + +bool FCDInput::Settings::deserialize(const QByteArray& data) +{ + resetToDefaults(); + return true; +} + +FCDInput::FCDInput(MessageQueue* msgQueueToGUI) : + SampleSource(msgQueueToGUI), + m_settings(), + m_FCDThread(NULL), + m_deviceDescription() +{ +} + +FCDInput::~FCDInput() +{ + stopInput(); +} + +bool FCDInput::startInput(int device) +{ + QMutexLocker mutexLocker(&m_mutex); + + if(m_FCDThread) + return false; + + if(!m_sampleFifo.setSize(4096*16)) { + qCritical("Could not allocate SampleFifo"); + return false; + } + + if((m_FCDThread = new FCDThread(&m_sampleFifo)) == NULL) { + qFatal("out of memory"); + return false; + } + + m_deviceDescription = QString("Funcube Dongle"); + + qDebug("FCDInput: start"); + return true; +} + +void FCDInput::stopInput() +{ + QMutexLocker mutexLocker(&m_mutex); + + if(m_FCDThread) { + m_FCDThread->stopWork(); + // wait for thread to quit ? + delete m_FCDThread; + m_FCDThread = NULL; + } + m_deviceDescription.clear(); +} + +const QString& FCDInput::getDeviceDescription() const +{ + return m_deviceDescription; +} + +int FCDInput::getSampleRate() const +{ + return 192000; +} + +quint64 FCDInput::getCenterFrequency() const +{ + return m_generalSettings.m_centerFrequency; +} + +bool FCDInput::handleMessage(Message* message) +{ + if(MsgConfigureFCD::match(message)) { + MsgConfigureFCD* conf = (MsgConfigureFCD*)message; + if(!applySettings(conf->getGeneralSettings(), conf->getSettings(), false)) + qDebug("FCD config error"); + message->completed(); + return true; + } else { + return false; + } +} + +bool FCDInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force) +{ + QMutexLocker mutexLocker(&m_mutex); + + if((m_generalSettings.m_centerFrequency != generalSettings.m_centerFrequency) || force) { + m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency; + if(m_FCDThread) + m_FCDThread->set_center_freq( (double)(generalSettings.m_centerFrequency) ); + } + return true; +} diff --git a/plugins/samplesource/fcd/fcdinput.h b/plugins/samplesource/fcd/fcdinput.h new file mode 100644 index 000000000..02610649d --- /dev/null +++ b/plugins/samplesource/fcd/fcdinput.h @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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_FCDINPUT_H +#define INCLUDE_FCDINPUT_H + +#include "dsp/samplesource/samplesource.h" +#include + +struct fcd_buffer { + void *start; + size_t length; +}; + +class FCDThread; + +class FCDInput : public SampleSource { +public: + struct Settings { + Settings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + }; + + class MsgConfigureFCD : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const GeneralSettings& getGeneralSettings() const { return m_generalSettings; } + const Settings& getSettings() const { return m_settings; } + + static MsgConfigureFCD* create(const GeneralSettings& generalSettings, const Settings& settings) + { + return new MsgConfigureFCD(generalSettings, settings); + } + + private: + GeneralSettings m_generalSettings; + Settings m_settings; + + MsgConfigureFCD(const GeneralSettings& generalSettings, const Settings& settings) : + Message(), + m_generalSettings(generalSettings), + m_settings(settings) + { } + }; + + + FCDInput(MessageQueue* msgQueueToGUI); + ~FCDInput(); + + bool startInput(int device); + void stopInput(); + + const QString& getDeviceDescription() const; + int getSampleRate() const; + quint64 getCenterFrequency() const; + bool handleMessage(Message* message); + +private: + QMutex m_mutex; + Settings m_settings; + FCDThread* m_FCDThread; + QString m_deviceDescription; + bool applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force); +}; + +#endif // INCLUDE_FCD_H diff --git a/plugins/samplesource/fcd/fcdplugin.cpp b/plugins/samplesource/fcd/fcdplugin.cpp new file mode 100644 index 000000000..a9b45db58 --- /dev/null +++ b/plugins/samplesource/fcd/fcdplugin.cpp @@ -0,0 +1,55 @@ +#include +#include +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "fcdplugin.h" +#include "fcdgui.h" + +const PluginDescriptor FCDPlugin::m_pluginDescriptor = { + QString("FunCube Input"), + QString("---"), + QString("(c) John Greb"), + QString("http://funcubedongle.com"), + true, + QString("___________") +}; + +FCDPlugin::FCDPlugin(QObject* parent) : + QObject(parent) +{ +} + +const PluginDescriptor& FCDPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void FCDPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcd", this); +} + +PluginInterface::SampleSourceDevices FCDPlugin::enumSampleSources() +{ + SampleSourceDevices result; + + QString displayedName(QString("Funcube Dongle #1")); + SimpleSerializer s(1); + s.writeS32(1, 0); + result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.fcd", s.final())); + + return result; +} + +PluginGUI* FCDPlugin::createSampleSource(const QString& sourceName, const QByteArray& address) +{ + if(sourceName == "org.osmocom.sdr.samplesource.fcd") { + FCDGui* gui = new FCDGui(m_pluginAPI); + m_pluginAPI->setInputGUI(gui); + return gui; + } else { + return NULL; + } +} diff --git a/plugins/samplesource/fcd/fcdplugin.h b/plugins/samplesource/fcd/fcdplugin.h new file mode 100644 index 000000000..e9818d812 --- /dev/null +++ b/plugins/samplesource/fcd/fcdplugin.h @@ -0,0 +1,27 @@ +#ifndef INCLUDE_FCDPLUGIN_H +#define INCLUDE_FCDPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class FCDPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcd") + +public: + explicit FCDPlugin(QObject* parent = NULL); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + SampleSourceDevices enumSampleSources(); + PluginGUI* createSampleSource(const QString& sourceName, const QByteArray& address); + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_FCDPLUGIN_H diff --git a/plugins/samplesource/fcd/fcdsource.cpp b/plugins/samplesource/fcd/fcdsource.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/samplesource/fcd/fcdthread.cpp b/plugins/samplesource/fcd/fcdthread.cpp new file mode 100644 index 000000000..8628094e6 --- /dev/null +++ b/plugins/samplesource/fcd/fcdthread.cpp @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "fcdthread.h" +#include "dsp/samplefifo.h" + +FCDThread::FCDThread(SampleFifo* sampleFifo, QObject* parent) : + QThread(parent), + m_running(false), + m_convertBuffer(BLOCKSIZE), + m_sampleFifo(sampleFifo) +{ + start(); +} + +FCDThread::~FCDThread() +{ +} + +void FCDThread::stopWork() +{ + m_running = false; + wait(); +} + +void FCDThread::run() +{ + m_running = true; + OpenSource("/dev/dsp"); + if (fd < 0) + return; + + while(m_running) { + work(BLOCKSIZE); + } + CloseSource(); +} + diff --git a/plugins/samplesource/fcd/fcdthread.h b/plugins/samplesource/fcd/fcdthread.h new file mode 100644 index 000000000..e62c09c54 --- /dev/null +++ b/plugins/samplesource/fcd/fcdthread.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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_FCDTHREAD_H +#define INCLUDE_FCDTHREAD_H + +#include +#include +#include +#include "dsp/samplefifo.h" +#include "dsp/inthalfbandfilter.h" + +#define SAMPLERATE 192000 +#define BLOCKSIZE 8192 + +class FCDThread : public QThread { + Q_OBJECT + +public: + FCDThread(SampleFifo* sampleFifo, QObject* parent = NULL); + ~FCDThread(); + + void stopWork(); + void OpenSource(const char *filename); + void CloseSource(); + void set_center_freq(double freq); + int work(int n_items); +private: + int fd; + struct fcd_buffer *buffers; + unsigned int n_buffers; + void *recebuf_ptr; + unsigned int recebuf_len; + unsigned int recebuf_mmap_index; + + QMutex m_startWaitMutex; + QWaitCondition m_startWaiter; + bool m_running; + + SampleVector m_convertBuffer; + SampleFifo* m_sampleFifo; + + void run(); + +}; +#endif // INCLUDE_FCDTHREAD_H