diff options
author | Christian Daniel <cd@maintech.de> | 2013-03-22 15:54:17 +0100 |
---|---|---|
committer | Christian Daniel <cd@maintech.de> | 2013-03-22 15:54:17 +0100 |
commit | 46a84022aa5c2aa11051115bc6414249f48b90c6 (patch) | |
tree | bdb782d2799e3a0a4fb4c7e8baaccf300bf93beb /plugins | |
parent | ec109f5613251d65641bb2d91b2c8246cc4da09a (diff) |
add GNURadio input plugin
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/samplesource/gnuradio/CMakeLists.txt | 53 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradiogui.cpp | 266 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradiogui.h | 81 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradiogui.ui | 369 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradioinput.cpp | 234 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradioinput.h | 184 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradioplugin.cpp | 52 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradioplugin.h | 26 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradiothread.cpp | 145 | ||||
-rw-r--r-- | plugins/samplesource/gnuradio/gnuradiothread.h | 64 |
10 files changed, 1474 insertions, 0 deletions
diff --git a/plugins/samplesource/gnuradio/CMakeLists.txt b/plugins/samplesource/gnuradio/CMakeLists.txt new file mode 100644 index 0000000..e1205b4 --- /dev/null +++ b/plugins/samplesource/gnuradio/CMakeLists.txt @@ -0,0 +1,53 @@ +project(gnuradio) + +set(gnuradio_SOURCES + gnuradiogui.cpp + gnuradioinput.cpp + gnuradioplugin.cpp + gnuradiothread.cpp +) + +set(gnuradio_HEADERS + gnuradiogui.h + gnuradioinput.h + gnuradioplugin.h + gnuradiothread.h +) + +set(gnuradio_FORMS + gnuradiogui.ui +) + +include_directories( + . + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/include-gpl + ${Boost_INCLUDE_DIRS} + ${GRUEL_INCLUDE_DIRS} + ${GNURADIO_CORE_INCLUDE_DIRS} + ${GNURADIO_OSMOSDR_INCLUDE_DIRS} +) + +include(${QT_USE_FILE}) +add_definitions(${QT_DEFINITIONS}) +add_definitions(-DQT_PLUGIN) +add_definitions(-DQT_SHARED) + +qt4_wrap_cpp(gnuradio_HEADERS_MOC ${gnuradio_HEADERS}) +qt4_wrap_ui(gnuradio_FORMS_HEADERS ${gnuradio_FORMS}) + +add_library(inputgnuradio SHARED + ${gnuradio_SOURCES} + ${gnuradio_HEADERS_MOC} + ${gnuradio_FORMS_HEADERS} +) + +target_link_libraries(inputgnuradio + ${QT_LIBRARIES} + ${LIBUSB_LIBRARIES} + ${Boost_LIBRARIES} + ${GRUEL_LIBRARIES} + ${GNURADIO_CORE_LIBRARIES} + ${GNURADIO_OSMOSDR_LIBRARIES} +) diff --git a/plugins/samplesource/gnuradio/gnuradiogui.cpp b/plugins/samplesource/gnuradio/gnuradiogui.cpp new file mode 100644 index 0000000..919708d --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradiogui.cpp @@ -0,0 +1,266 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net> // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#include "gnuradiogui.h" +#include "ui_gnuradiogui.h" + +#include <osmosdr_device.h> +#include <boost/foreach.hpp> +#include <iostream> +#include <plugin/pluginapi.h> + +GNURadioGui::GNURadioGui(PluginAPI* pluginAPI, QWidget* parent) : + PluginGUI(parent), + ui(new Ui::GNURadioGui), + m_pluginAPI(pluginAPI), + m_settings(), + m_sampleSource(NULL) +{ + ui->setupUi(this); + ui->centerFrequency->setValueRange(7, 20000U, 2200000U); + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); + displaySettings(); + + m_sampleSource = new GNURadioInput(m_pluginAPI->getMainWindowMessageQueue()); + m_pluginAPI->setSampleSource(m_sampleSource); +} + +GNURadioGui::~GNURadioGui() +{ + delete ui; +} + +void GNURadioGui::destroy() +{ + delete this; +} + +void GNURadioGui::resetToDefaults() +{ + m_generalSettings.resetToDefaults(); + m_settings.resetToDefaults(); + displaySettings(); + sendSettings(); +} + +QByteArray GNURadioGui::serializeGeneral() const +{ + return m_generalSettings.serialize(); +} + +bool GNURadioGui::deserializeGeneral(const QByteArray&data) +{ + if(m_generalSettings.deserialize(data)) { + displaySettings(); + sendSettings(); + return true; + } else { + resetToDefaults(); + return false; + } +} + +quint64 GNURadioGui::getCenterFrequency() const +{ + return m_generalSettings.m_centerFrequency; +} + +QByteArray GNURadioGui::serialize() const +{ + return m_settings.serialize(); +} + +bool GNURadioGui::deserialize(const QByteArray& data) +{ + if(m_settings.deserialize(data)) { + displaySettings(); + sendSettings(); + return true; + } else { + resetToDefaults(); + return false; + } +} + +bool GNURadioGui::handleMessage(Message* message) +{ + if(message->id() == GNURadioInput::MsgReportGNURadio::ID()) { + GNURadioInput::MsgReportGNURadio* rep = (GNURadioInput::MsgReportGNURadio*)message; + m_rfGains = rep->getRfGains(); + m_ifGains = rep->getIfGains(); + m_sampRates = rep->getSampRates(); + m_antennas = rep->getAntennas(); + displaySettings(); + return true; + } else { + return false; + } +} + +void GNURadioGui::displaySettings() +{ + int oldIndex = 0; + + oldIndex = ui->gnuradioDevices->currentIndex(); + ui->gnuradioDevices->clear(); + + BOOST_FOREACH(osmosdr::device_t dev, osmosdr::device::find()) + { + QString label; + + if ( dev.count( "label" ) ) { + label = QString(dev[ "label" ].c_str()); + dev.erase("label"); + } + + QPair< QString, QString > pair(label, dev.to_string().c_str()); + m_devs.append(pair); + + ui->gnuradioDevices->addItem(label); + } + + if ( ui->gnuradioDevices->count() && oldIndex >= 0 ) + { + ui->gnuradioDevices->setCurrentIndex(oldIndex); + ui->deviceArguments->setText(m_devs[oldIndex].second); + } + + ui->centerFrequency->setValue(m_generalSettings.m_centerFrequency / 1000); + + if ( m_rfGains.size() ) { + oldIndex = ui->sldRfGain->value(); + ui->sldRfGain->setMinimum(0); + ui->sldRfGain->setMaximum(m_rfGains.size() - 1); + ui->sldRfGain->setValue(oldIndex == 0 ? m_rfGains.size() / 2 : oldIndex); + ui->sldRfGain->setEnabled(true); + } else { + ui->sldRfGain->setEnabled(false); + } + + if ( m_ifGains.size() ) { + oldIndex = ui->sldIfGain->value(); + ui->sldIfGain->setMinimum(0); + ui->sldIfGain->setMaximum(m_ifGains.size() - 1); + ui->sldIfGain->setValue(oldIndex == 0 ? m_ifGains.size() / 2 : oldIndex); + ui->sldIfGain->setEnabled(true); + } else { + ui->sldIfGain->setEnabled(false); + } + + oldIndex = ui->cboSampleRate->currentIndex(); + ui->cboSampleRate->clear(); + + for ( int i = 0; i < m_sampRates.size(); i++ ) + ui->cboSampleRate->addItem(QString("%1").arg( m_sampRates[i] )); + + if ( ui->cboSampleRate->count() && oldIndex >= 0 ) + ui->cboSampleRate->setCurrentIndex(oldIndex); + + oldIndex = ui->cboAntennas->currentIndex(); + ui->cboAntennas->clear(); + + if ( m_antennas.size() ) { + for ( int i = 0; i < m_antennas.size(); i++ ) + ui->cboAntennas->addItem(QString("%1").arg( m_antennas[i] )); + + if ( ui->cboAntennas->count() && oldIndex >= 0 ) + ui->cboAntennas->setCurrentIndex(oldIndex); + + ui->cboAntennas->setEnabled(true); + } else { + ui->cboAntennas->setEnabled(false); + } +} + +void GNURadioGui::sendSettings() +{ + if(!m_updateTimer.isActive()) + m_updateTimer.start(100); +} + +void GNURadioGui::updateHardware() +{ + m_updateTimer.stop(); + GNURadioInput::MsgConfigureGNURadio* msg = GNURadioInput::MsgConfigureGNURadio::create(m_generalSettings, m_settings); + msg->submit(m_pluginAPI->getDSPEngineMessageQueue()); +} + +void GNURadioGui::on_gnuradioDevices_currentIndexChanged(int index) +{ + if ( index < 0 || index >= m_devs.count() ) + return; + + ui->deviceArguments->setText(m_devs[index].second); +} + +void GNURadioGui::on_centerFrequency_changed(quint64 value) +{ + m_generalSettings.m_centerFrequency = value * 1000; + sendSettings(); +} + +void GNURadioGui::on_sldFreqCorr_valueChanged(int value) +{ + ui->lblFreqCorrValue->setText(tr("%1").arg(value)); + m_settings.m_freqCorr = value; + sendSettings(); +} + +void GNURadioGui::on_sldRfGain_valueChanged(int value) +{ + if ( value >= m_rfGains.size() ) + return; + + double gain = m_rfGains[value]; + ui->lblRfGainValue->setText(tr("%1").arg(gain)); + m_settings.m_rfGain = gain; + sendSettings(); +} + +void GNURadioGui::on_sldIfGain_valueChanged(int value) +{ + if ( value >= m_ifGains.size() ) + return; + + double gain = m_ifGains[value]; + ui->lblIfGainValue->setText(tr("%1").arg(gain)); + m_settings.m_ifGain = gain; + sendSettings(); +} + +void GNURadioGui::on_cboSampleRate_currentIndexChanged(int index) +{ + if ( index < 0 || index >= m_sampRates.size() ) + return; + + m_settings.m_sampleRate = m_sampRates[index]; + sendSettings(); +} + +void GNURadioGui::on_deviceArguments_textChanged(const QString &arg1) +{ + m_settings.m_args = arg1; + sendSettings(); +} + +void GNURadioGui::on_cboAntennas_currentIndexChanged(const QString &arg1) +{ + m_settings.m_antenna = arg1; + std::cout << arg1.toStdString() << std::endl; + sendSettings(); +} diff --git a/plugins/samplesource/gnuradio/gnuradiogui.h b/plugins/samplesource/gnuradio/gnuradiogui.h new file mode 100644 index 0000000..e23d291 --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradiogui.h @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net> // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_GNURADIOGUI_H +#define INCLUDE_GNURADIOGUI_H + +#include <QTimer> +#include <QPair> +#include <QList> +#include <QString> +#include "plugin/plugingui.h" +#include "gnuradioinput.h" + +namespace Ui { + class GNURadioGui; +} + +class PluginAPI; + +class GNURadioGui : public PluginGUI { + Q_OBJECT + +public: + explicit GNURadioGui(PluginAPI* pluginAPI, QWidget* parent = NULL); + ~GNURadioGui(); + void destroy(); + + 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::GNURadioGui* ui; + PluginAPI* m_pluginAPI; + SampleSource* m_sampleSource; + QList< QPair<QString, QString> > m_devs; + std::vector<double> m_rfGains; + std::vector<double> m_ifGains; + std::vector<double> m_sampRates; + std::vector<QString> m_antennas; + + SampleSource::GeneralSettings m_generalSettings; + GNURadioInput::Settings m_settings; + QTimer m_updateTimer; + + void displaySettings(); + void sendSettings(); + +private slots: + void updateHardware(); + + void on_gnuradioDevices_currentIndexChanged(int index); + void on_centerFrequency_changed(quint64 value); + void on_sldFreqCorr_valueChanged(int value); + void on_sldRfGain_valueChanged(int value); + void on_sldIfGain_valueChanged(int value); + void on_cboSampleRate_currentIndexChanged(int index); + void on_deviceArguments_textChanged(const QString &arg1); + void on_cboAntennas_currentIndexChanged(const QString &arg1); +}; + +#endif // INCLUDE_GNURADIOGUI_H diff --git a/plugins/samplesource/gnuradio/gnuradiogui.ui b/plugins/samplesource/gnuradio/gnuradiogui.ui new file mode 100644 index 0000000..69ecdb7 --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradiogui.ui @@ -0,0 +1,369 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>GNURadioGui</class> + <widget class="QWidget" name="GNURadioGui"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>254</width> + <height>239</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Gnuradio Source</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="margin"> + <number>2</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>2</number> + </property> + <item> + <widget class="QComboBox" name="gnuradioDevices"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>false</bool> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLength</enum> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="deviceArguments"> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="ValueDial" name="centerFrequency" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>16</height> + </size> + </property> + <property name="font"> + <font> + <family>Monospace</family> + <pointsize>20</pointsize> + </font> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Tuner center frequency in kHz</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Freq. Corr.</string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="sldFreqCorr"> + <property name="minimum"> + <number>-100</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="tracking"> + <bool>true</bool> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblFreqCorrValue"> + <property name="minimumSize"> + <size> + <width>40</width> + <height>0</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <widget class="QLabel" name="lblRfGainText"> + <property name="text"> + <string>RF Gain </string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="sldRfGain"> + <property name="toolTip"> + <string/> + </property> + <property name="maximum"> + <number>9</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::NoTicks</enum> + </property> + <property name="tickInterval"> + <number>0</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblRfGainValue"> + <property name="minimumSize"> + <size> + <width>40</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <widget class="QLabel" name="lblIfGain"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>IF Gain </string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="sldIfGain"> + <property name="toolTip"> + <string/> + </property> + <property name="maximum"> + <number>9</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblIfGainValue"> + <property name="minimumSize"> + <size> + <width>40</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Sample Rate</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="cboSampleRate"> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLength</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Antenna</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="cboAntennas"/> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ValueDial</class> + <extends>QWidget</extends> + <header>gui/valuedial.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/plugins/samplesource/gnuradio/gnuradioinput.cpp b/plugins/samplesource/gnuradio/gnuradioinput.cpp new file mode 100644 index 0000000..c9d8ec3 --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradioinput.cpp @@ -0,0 +1,234 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net> // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#include <string.h> +#include <errno.h> +#include <boost/foreach.hpp> +#include "util/simpleserializer.h" +#include "gnuradioinput.h" +#include "gnuradiothread.h" +#include "gnuradiogui.h" + +MessageRegistrator GNURadioInput::MsgConfigureGNURadio::ID("MsgConfigureGNURadio"); +MessageRegistrator GNURadioInput::MsgReportGNURadio::ID("MsgReportGNURadio"); + +GNURadioInput::Settings::Settings() : + m_args(""), + m_sampleRate(2e6), + m_freqCorr(0), + m_rfGain(10), + m_ifGain(15), + m_antenna("") +{ +} + +void GNURadioInput::Settings::resetToDefaults() +{ + m_args = ""; + m_sampleRate = 2e6; + m_freqCorr = 0; + m_rfGain = 10; + m_ifGain = 15; + m_antenna = ""; +} + +QByteArray GNURadioInput::Settings::serialize() const +{ + SimpleSerializer s(1); + s.writeString(1, m_args); + s.writeDouble(2, m_sampleRate); + s.writeDouble(3, m_freqCorr); + s.writeDouble(4, m_rfGain); + s.writeDouble(5, m_ifGain); + s.writeString(6, m_antenna); + return s.final(); +} + +bool GNURadioInput::Settings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) { + d.readString(1, &m_args, ""); + d.readDouble(2, &m_sampleRate, 2e6); + d.readDouble(3, &m_freqCorr, 0); + d.readDouble(4, &m_rfGain, 10); + d.readDouble(5, &m_ifGain, 15); + d.readString(6, &m_antenna, ""); + return true; + } else { + resetToDefaults(); + return false; + } +} + +GNURadioInput::GNURadioInput(MessageQueue* msgQueueToGUI) : + SampleSource(msgQueueToGUI), + m_settings(), + m_GnuradioThread(NULL), + m_deviceDescription() +{ +} + +GNURadioInput::~GNURadioInput() +{ + stopInput(); +} + +bool GNURadioInput::startInput(int device) +{ + QMutexLocker mutexLocker(&m_mutex); + + if(m_GnuradioThread != NULL) + stopInput(); + + if(!m_sampleFifo.setSize(524288)) { + qCritical("Could not allocate SampleFifo"); + return false; + } + + m_deviceDescription = m_settings.m_args; + + // pass device arguments from the gui + m_GnuradioThread = new GnuradioThread(m_settings.m_args, &m_sampleFifo); + if(m_GnuradioThread == NULL) { + qFatal("out of memory"); + goto failed; + } + m_GnuradioThread->startWork(); + + mutexLocker.unlock(); + applySettings(m_generalSettings, m_settings, true); + + if(m_GnuradioThread != NULL) { + osmosdr_source_c_sptr radio = m_GnuradioThread->radio(); + + m_sampRates = radio->get_sample_rates().values(); + m_rfGains = radio->get_gain_range().values(); + m_ifGains = radio->get_gain_range("IF").values(); + + m_antennas.clear(); + BOOST_FOREACH( std::string antenna, radio->get_antennas() ) + m_antennas.push_back( QString( antenna.c_str() ) ); + } + + qDebug("GnuradioInput: start"); + MsgReportGNURadio::create(m_rfGains, m_ifGains, m_sampRates, m_antennas)->submit(m_guiMessageQueue); + + return true; + +failed: + stopInput(); + return false; +} + +void GNURadioInput::stopInput() +{ + QMutexLocker mutexLocker(&m_mutex); + + if(m_GnuradioThread != NULL) { + m_GnuradioThread->stopWork(); + delete m_GnuradioThread; + m_GnuradioThread = NULL; + } + + m_deviceDescription.clear(); +} + +const QString& GNURadioInput::getDeviceDescription() const +{ + return m_deviceDescription; +} + +int GNURadioInput::getSampleRate() const +{ + return m_settings.m_sampleRate; +} + +quint64 GNURadioInput::getCenterFrequency() const +{ + return m_generalSettings.m_centerFrequency; +} + +bool GNURadioInput::handleMessage(Message* message) +{ + if(message->id() == MsgConfigureGNURadio::ID()) { + MsgConfigureGNURadio* conf = (MsgConfigureGNURadio*)message; + if(!applySettings(conf->getGeneralSettings(), conf->getSettings(), false)) + qDebug("Gnuradio config error"); + return true; + } else { + return false; + } +} + +bool GNURadioInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force) +{ + QMutexLocker mutexLocker(&m_mutex); + + m_settings.m_args = settings.m_args; + + if((m_settings.m_freqCorr != settings.m_freqCorr) || force) { + m_settings.m_freqCorr = settings.m_freqCorr; + if(m_GnuradioThread != NULL) { + m_GnuradioThread->radio()->set_freq_corr( m_settings.m_freqCorr ); + } + } + + if((m_generalSettings.m_centerFrequency != generalSettings.m_centerFrequency) || force) { + m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency; + if(m_GnuradioThread != NULL) { + m_GnuradioThread->radio()->set_center_freq( m_generalSettings.m_centerFrequency ); + } + } + + if((m_settings.m_rfGain != settings.m_rfGain) || force) { + m_settings.m_rfGain = settings.m_rfGain; + if(m_GnuradioThread != NULL) { + m_GnuradioThread->radio()->set_gain( m_settings.m_rfGain ); + } + } + + if((m_settings.m_ifGain != settings.m_ifGain) || force) { + m_settings.m_ifGain = settings.m_ifGain; + if(m_GnuradioThread != NULL) { + m_GnuradioThread->radio()->set_gain( m_settings.m_ifGain, "IF" ); + } + } + + if((m_settings.m_sampleRate != settings.m_sampleRate) || force) { + m_settings.m_sampleRate = settings.m_sampleRate; + if(m_GnuradioThread != NULL) { + m_GnuradioThread->radio()->set_sample_rate( m_settings.m_sampleRate ); + } + } + + if((m_settings.m_antenna != settings.m_antenna) || force) { + m_settings.m_antenna = settings.m_antenna; + if(m_GnuradioThread != NULL) { + m_GnuradioThread->radio()->set_antenna( m_settings.m_antenna.toStdString() ); + } + } + + return true; +} diff --git a/plugins/samplesource/gnuradio/gnuradioinput.h b/plugins/samplesource/gnuradio/gnuradioinput.h new file mode 100644 index 0000000..6ff6513 --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradioinput.h @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net> // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_GNURADIOINPUT_H +#define INCLUDE_GNURADIOINPUT_H + +#include "dsp/samplesource/samplesource.h" +#include <QString> + +class GnuradioThread; + +class GNURadioInput : public SampleSource { +public: + struct Settings { + QString m_args; + double m_sampleRate; + double m_freqCorr; + double m_rfGain; + double m_ifGain; + QString m_antenna; + + Settings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + }; + + class MsgConfigureGNURadio : public Message { + public: + static MessageRegistrator ID; + + const GeneralSettings& getGeneralSettings() const { return m_generalSettings; } + const Settings& getSettings() const { return m_settings; } + + static MsgConfigureGNURadio* create(const GeneralSettings& generalSettings, const Settings& settings) + { + return new MsgConfigureGNURadio(generalSettings, settings); + } + + protected: + GeneralSettings m_generalSettings; + Settings m_settings; + + MsgConfigureGNURadio(const GeneralSettings& generalSettings, const Settings& settings) : + Message(ID()), + m_generalSettings(generalSettings), + m_settings(settings) + { } + }; + + class MsgReportGNURadio : public Message { + public: + static MessageRegistrator ID; + + const std::vector<double>& getRfGains() const { return m_rfGains; } + const std::vector<double>& getIfGains() const { return m_ifGains; } + const std::vector<double>& getSampRates() const { return m_sampRates; } + const std::vector<QString>& getAntennas() const { return m_antennas; } + + static MsgReportGNURadio* create(const std::vector<double>& rfGains, + const std::vector<double>& ifGains, + const std::vector<double>& sampRates, + const std::vector<QString>& antennas) + { + return new MsgReportGNURadio(rfGains, ifGains, sampRates, antennas); + } + + protected: + std::vector<double> m_rfGains; + std::vector<double> m_ifGains; + std::vector<double> m_sampRates; + std::vector<QString> m_antennas; + + MsgReportGNURadio(const std::vector<double>& rfGains, + const std::vector<double>& ifGains, + const std::vector<double>& sampRates, + const std::vector<QString>& antennas) : + Message(ID()), + m_rfGains(rfGains), + m_ifGains(ifGains), + m_sampRates(sampRates), + m_antennas(antennas) + { } + }; + + GNURadioInput(MessageQueue* msgQueueToGUI); + ~GNURadioInput(); + + 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; + GnuradioThread* m_GnuradioThread; + QString m_deviceDescription; + std::vector<double> m_rfGains; + std::vector<double> m_ifGains; + std::vector<double> m_sampRates; + std::vector<QString> m_antennas; + + bool applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force); +}; +#if 0 +class DSPCmdConfigureSourceGnuradio : public DSPCmdGUIToSource { +public: + enum { + SourceType = 3 + }; + + int sourceType() const; + const GnuradioInput::Settings& getSettings() const { return m_settings; } + + static DSPCmdConfigureSourceGnuradio* create(const GnuradioInput::Settings& settings) + { + return new DSPCmdConfigureSourceGnuradio(settings); + } + +protected: + GnuradioInput::Settings m_settings; + + DSPCmdConfigureSourceGnuradio(const GnuradioInput::Settings& settings) : m_settings(settings) { } +}; +#endif +#if 0 +class DSPCmdGUIInfoGnuradio : public DSPCmdSourceToGUI { +public: + enum { + SourceType = 3 + }; + + int sourceType() const; + const std::vector<double>& getRfGains() const { return m_rfGains; } + const std::vector<double>& getIfGains() const { return m_ifGains; } + const std::vector<double>& getSampRates() const { return m_sampRates; } + const std::vector<QString>& getAntennas() const { return m_antennas; } + + static DSPCmdGUIInfoGnuradio* create(const std::vector<double>& rfGains, + const std::vector<double>& ifGains, + const std::vector<double>& sampRates, + const std::vector<QString>& antennas) + { + return new DSPCmdGUIInfoGnuradio(rfGains, ifGains, sampRates, antennas); + } + +protected: + std::vector<double> m_rfGains; + std::vector<double> m_ifGains; + std::vector<double> m_sampRates; + std::vector<QString> m_antennas; + + DSPCmdGUIInfoGnuradio(const std::vector<double>& rfGains, + const std::vector<double>& ifGains, + const std::vector<double>& sampRates, + const std::vector<QString>& antennas) : + m_rfGains(rfGains), + m_ifGains(ifGains), + m_sampRates(sampRates), + m_antennas(antennas) + { } +}; +#endif +#endif // INCLUDE_GNURADIOINPUT_H diff --git a/plugins/samplesource/gnuradio/gnuradioplugin.cpp b/plugins/samplesource/gnuradio/gnuradioplugin.cpp new file mode 100644 index 0000000..bebbba8 --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradioplugin.cpp @@ -0,0 +1,52 @@ +#include <QtPlugin> +#include <QAction> +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "gnuradioplugin.h" +#include "gnuradiogui.h" + +const PluginDescriptor GNURadioPlugin::m_pluginDescriptor = { + displayedName: QString("GR-OsmoSDR Input"), + version: QString("---"), + copyright: QString("(c) Dimitri Stolnikov <horiz0n@gmx.net>"), + website: QString("http://sdr.osmocom.org/trac/wiki/gr-osmosdr"), + licenseIsGPL: true, + sourceCodeURL: QString("http://cgit.osmocom.org/cgit/gr-osmosdr") +}; + +GNURadioPlugin::GNURadioPlugin(QObject* parent) : + QObject(parent) +{ +} + +const PluginDescriptor& GNURadioPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void GNURadioPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.gr-osmosdr", this); +} + +PluginInterface::SampleSourceDevices GNURadioPlugin::enumSampleSources() +{ + SampleSourceDevices result; + + result.append(SampleSourceDevice("GNURadio OsmoSDR Driver", "org.osmocom.sdr.samplesource.gr-osmosdr", QByteArray())); + + return result; +} + +PluginGUI* GNURadioPlugin::createSampleSource(const QString& sourceName, const QByteArray& address) +{ + if(sourceName == "org.osmocom.sdr.samplesource.gr-osmosdr") { + return new GNURadioGui(m_pluginAPI); + } else { + return NULL; + } +} + +Q_EXPORT_PLUGIN2(gnuRadioPlugin, GNURadioPlugin); diff --git a/plugins/samplesource/gnuradio/gnuradioplugin.h b/plugins/samplesource/gnuradio/gnuradioplugin.h new file mode 100644 index 0000000..092469f --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradioplugin.h @@ -0,0 +1,26 @@ +#ifndef INCLUDE_GNURADIOPLUGIN_H +#define INCLUDE_GNURADIOPLUGIN_H + +#include <QObject> +#include "plugin/plugininterface.h" + +class GNURadioPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + +public: + explicit GNURadioPlugin(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_GNURADIOPLUGIN_H diff --git a/plugins/samplesource/gnuradio/gnuradiothread.cpp b/plugins/samplesource/gnuradio/gnuradiothread.cpp new file mode 100644 index 0000000..c67de8c --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradiothread.cpp @@ -0,0 +1,145 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net> // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <errno.h> +#include "gnuradiothread.h" +#include "dsp/samplefifo.h" + +#include <gr_sync_block.h> +#include <gr_io_signature.h> + +//////////////////////////////////////////////////////////////////////////////// +class gr_adaptor; + +typedef boost::shared_ptr<gr_adaptor> gr_adaptor_sptr; + +gr_adaptor_sptr make_gr_adaptor (SampleFifo* sampleFifo); + +class gr_adaptor : public gr_sync_block +{ +public: + gr_adaptor (SampleFifo* sampleFifo); + ~gr_adaptor (); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + +private: + SampleFifo *m_sampleFifo; +}; + +gr_adaptor_sptr +make_gr_adaptor (SampleFifo *sampleFifo) +{ + return gr_adaptor_sptr (new gr_adaptor (sampleFifo)); +} + +gr_adaptor::gr_adaptor (SampleFifo *sampleFifo) + : gr_sync_block ("gr_adaptor", + gr_make_io_signature (1, 1, sizeof (gr_complex)), + gr_make_io_signature (0, 0, 0)), + m_sampleFifo(sampleFifo) +{ +} + +gr_adaptor::~gr_adaptor () +{ +} + +int +gr_adaptor::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + std::vector<qint16> buffer(noutput_items * 2, 0); + std::vector<qint16>::iterator it = buffer.begin(); + + for (int i = 0; i < noutput_items; i++) + { + *it++ = in[i].real() * 32000; + *it++ = in[i].imag() * 32000; + } + + // we must push at least 4 bytes into the fifo + m_sampleFifo->write((const quint8*)buffer.data(), + (it - buffer.begin()) * sizeof(qint16)); + + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each(noutput_items); + + // Tell runtime system how many output items we produced. + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +GnuradioThread::GnuradioThread(QString args, SampleFifo* sampleFifo, QObject* parent) : + QThread(parent), + m_running(false), + m_args(args), + m_sampleFifo(sampleFifo) +{ +} + +GnuradioThread::~GnuradioThread() +{ + stopWork(); +} + +void GnuradioThread::startWork() +{ + m_startWaitMutex.lock(); + + start(); + while(!m_running) + m_startWaiter.wait(&m_startWaitMutex, 100); + + m_startWaitMutex.unlock(); +} + +void GnuradioThread::stopWork() +{ + m_running = false; + + m_top->stop(); + + wait(); +} + +void GnuradioThread::run() +{ + m_top = gr_make_top_block( "flowgraph" ); + m_src = osmosdr_make_source_c( m_args.toStdString() ); + + /* now since we've constructed our shared objects, we allow the calling + * thread to continue it's work and send some radio settings to us. */ + m_running = true; + m_startWaiter.wakeAll(); + + gr_adaptor_sptr adaptor = make_gr_adaptor(m_sampleFifo); + m_top->connect(m_src, 0, adaptor, 0); + + m_top->run(); + + m_running = false; +} diff --git a/plugins/samplesource/gnuradio/gnuradiothread.h b/plugins/samplesource/gnuradio/gnuradiothread.h new file mode 100644 index 0000000..c098a47 --- /dev/null +++ b/plugins/samplesource/gnuradio/gnuradiothread.h @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// Copyright (C) 2013 by Dimitri Stolnikov <horiz0n@gmx.net> // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_GNURADIOTHREAD_H +#define INCLUDE_GNURADIOTHREAD_H + +#include <QThread> +#include <QMutex> +#include <QWaitCondition> + +#include <gr_top_block.h> +#include <osmosdr_source_c.h> + +class SampleFifo; + +class GnuradioThread : public QThread { + Q_OBJECT + +public: + GnuradioThread(QString args, SampleFifo* sampleFifo, QObject* parent = NULL); + ~GnuradioThread(); + + void startWork(); + void stopWork(); + + osmosdr_source_c_sptr radio() { return m_src; } + +private: +#pragma pack(push, 1) + struct Sample { + qint16 i; + qint16 q; + }; +#pragma pack(pop) + + QMutex m_startWaitMutex; + QWaitCondition m_startWaiter; + bool m_running; + + QString m_args; + SampleFifo* m_sampleFifo; + + gr_top_block_sptr m_top; + osmosdr_source_c_sptr m_src; + + void run(); +}; + +#endif // INCLUDE_GNURADIOTHREAD_H |