diff --git a/plugins/samplesource/CMakeLists.txt b/plugins/samplesource/CMakeLists.txt
index 032b0b2eb..5e1ec48eb 100644
--- a/plugins/samplesource/CMakeLists.txt
+++ b/plugins/samplesource/CMakeLists.txt
@@ -43,3 +43,4 @@ if(LIBUSB_FOUND AND LIBHACKRF_FOUND)
endif(LIBUSB_FOUND AND LIBHACKRF_FOUND)
add_subdirectory(filesource)
+add_subdirectory(sdrdaemon)
diff --git a/plugins/samplesource/sdrdaemon/CMakeLists.txt b/plugins/samplesource/sdrdaemon/CMakeLists.txt
new file mode 100644
index 000000000..f693b6adb
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/CMakeLists.txt
@@ -0,0 +1,49 @@
+project(sdrdaemon)
+
+set(sdrdaemon_SOURCES
+ sdrdaemongui.cpp
+ sdrdaemoninput.cpp
+ sdrdaemonplugin.cpp
+ sdrdaemonthread.cpp
+)
+
+set(sdrdaemon_HEADERS
+ sdrdaemongui.h
+ sdrdaemoninput.h
+ sdrdaemonplugin.h
+ sdrdaemonthread.h
+)
+
+set(sdrdaemon_FORMS
+ sdrdaemongui.ui
+)
+
+include_directories(
+ .
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/include-gpl
+ ${LIBRTLSDR_INCLUDE_DIR}
+)
+
+#include(${QT_USE_FILE})
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+
+#qt4_wrap_cpp(sdrdaemon_HEADERS_MOC ${sdrdaemon_HEADERS})
+qt5_wrap_ui(sdrdaemon_FORMS_HEADERS ${sdrdaemon_FORMS})
+
+add_library(inputsdrdaemon SHARED
+ ${sdrdaemon_SOURCES}
+ ${sdrdaemon_HEADERS_MOC}
+ ${sdrdaemon_FORMS_HEADERS}
+)
+
+target_link_libraries(inputsdrdaemon
+ ${QT_LIBRARIES}
+ ${LIBUSB_LIBRARIES}
+ sdrbase
+)
+
+qt5_use_modules(inputsdrdaemon Core Widgets OpenGL Multimedia)
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemongui.cpp b/plugins/samplesource/sdrdaemon/sdrdaemongui.cpp
new file mode 100644
index 000000000..b8dd917e3
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemongui.cpp
@@ -0,0 +1,241 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include
+#include
+#include
+#include
+#include "ui_sdrdaemongui.h"
+#include "plugin/pluginapi.h"
+#include "gui/colormapper.h"
+#include "dsp/dspengine.h"
+#include "mainwindow.h"
+
+#include "sdrdaemongui.h"
+
+SDRdaemonGui::SDRdaemonGui(PluginAPI* pluginAPI, QWidget* parent) :
+ QWidget(parent),
+ ui(new Ui::SDRdaemonGui),
+ m_pluginAPI(pluginAPI),
+ m_settings(),
+ m_sampleSource(NULL),
+ m_acquisition(false),
+ m_fileName("..."),
+ m_sampleRate(0),
+ m_centerFrequency(0),
+ m_startingTimeStamp(0),
+ m_samplesCount(0),
+ m_tickCount(0)
+{
+ ui->setupUi(this);
+ ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
+ ui->centerFrequency->setValueRange(7, 0, pow(10,7));
+ ui->fileNameText->setText(m_fileName);
+ connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
+ connect(&(m_pluginAPI->getMainWindow()->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
+ displaySettings();
+
+ m_sampleSource = new SDRdaemonInput(m_pluginAPI->getMainWindow()->getMasterTimer());
+ connect(m_sampleSource->getOutputMessageQueueToGUI(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
+ DSPEngine::instance()->setSource(m_sampleSource);
+}
+
+SDRdaemonGui::~SDRdaemonGui()
+{
+ delete ui;
+}
+
+void SDRdaemonGui::destroy()
+{
+ delete this;
+}
+
+void SDRdaemonGui::setName(const QString& name)
+{
+ setObjectName(name);
+}
+
+QString SDRdaemonGui::getName() const
+{
+ return objectName();
+}
+
+void SDRdaemonGui::resetToDefaults()
+{
+ m_settings.resetToDefaults();
+ displaySettings();
+ sendSettings();
+}
+
+qint64 SDRdaemonGui::getCenterFrequency() const
+{
+ return m_centerFrequency;
+}
+
+void SDRdaemonGui::setCenterFrequency(qint64 centerFrequency)
+{
+ m_centerFrequency = centerFrequency;
+ displaySettings();
+ sendSettings();
+}
+
+QByteArray SDRdaemonGui::serialize() const
+{
+ return m_settings.serialize();
+}
+
+bool SDRdaemonGui::deserialize(const QByteArray& data)
+{
+ if(m_settings.deserialize(data)) {
+ displaySettings();
+ sendSettings();
+ return true;
+ } else {
+ resetToDefaults();
+ return false;
+ }
+}
+
+bool SDRdaemonGui::handleMessage(const Message& message)
+{
+ if (SDRdaemonInput::MsgReportSDRdaemonAcquisition::match(message))
+ {
+ m_acquisition = ((SDRdaemonInput::MsgReportSDRdaemonAcquisition&)message).getAcquisition();
+ updateWithAcquisition();
+ return true;
+ }
+ else if (SDRdaemonInput::MsgReportSDRdaemonStreamData::match(message))
+ {
+ m_sampleRate = ((SDRdaemonInput::MsgReportSDRdaemonStreamData&)message).getSampleRate();
+ m_centerFrequency = ((SDRdaemonInput::MsgReportSDRdaemonStreamData&)message).getCenterFrequency();
+ m_startingTimeStamp = ((SDRdaemonInput::MsgReportSDRdaemonStreamData&)message).getStartingTimeStamp();
+ updateWithStreamData();
+ return true;
+ }
+ else if (SDRdaemonInput::MsgReportSDRdaemonStreamTiming::match(message))
+ {
+ m_samplesCount = ((SDRdaemonInput::MsgReportSDRdaemonStreamTiming&)message).getSamplesCount();
+ updateWithStreamTime();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void SDRdaemonGui::handleSourceMessages()
+{
+ Message* message;
+
+ while ((message = m_sampleSource->getOutputMessageQueueToGUI()->pop()) != 0)
+ {
+ qDebug("SDRdaemonGui::handleSourceMessages: message: %s", message->getIdentifier());
+
+ if (handleMessage(*message))
+ {
+ delete message;
+ }
+ }
+}
+
+void SDRdaemonGui::displaySettings()
+{
+}
+
+void SDRdaemonGui::sendSettings()
+{
+}
+
+void SDRdaemonGui::updateHardware()
+{
+}
+
+void SDRdaemonGui::on_play_toggled(bool checked)
+{
+ SDRdaemonInput::MsgConfigureSDRdaemonWork* message = SDRdaemonInput::MsgConfigureSDRdaemonWork::create(checked);
+ m_sampleSource->getInputMessageQueue()->push(message);
+}
+
+void SDRdaemonGui::on_showFileDialog_clicked(bool checked)
+{
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq)"));
+
+ if (fileName != "")
+ {
+ m_fileName = fileName;
+ ui->fileNameText->setText(m_fileName);
+ configureFileName();
+ }
+}
+
+void SDRdaemonGui::configureFileName()
+{
+ qDebug() << "SDRdaemonGui::configureFileName: " << m_fileName.toStdString().c_str();
+ SDRdaemonInput::MsgConfigureSDRdaemonName* message = SDRdaemonInput::MsgConfigureSDRdaemonName::create(m_fileName);
+ m_sampleSource->getInputMessageQueue()->push(message);
+}
+
+void SDRdaemonGui::updateWithAcquisition()
+{
+ ui->play->setEnabled(m_acquisition);
+ ui->play->setChecked(m_acquisition);
+ ui->showFileDialog->setEnabled(!m_acquisition);
+}
+
+void SDRdaemonGui::updateWithStreamData()
+{
+ ui->centerFrequency->setValue(m_centerFrequency/1000);
+ QString s = QString::number(m_sampleRate/1000.0, 'f', 0);
+ ui->sampleRateText->setText(tr("%1k").arg(s));
+ ui->play->setEnabled(m_acquisition);
+ updateWithStreamTime(); // TODO: remove when time data is implemented
+}
+
+void SDRdaemonGui::updateWithStreamTime()
+{
+ int t_sec = 0;
+ int t_msec = 0;
+
+ if (m_sampleRate > 0){
+ t_msec = ((m_samplesCount * 1000) / m_sampleRate) % 1000;
+ t_sec = m_samplesCount / m_sampleRate;
+ }
+
+ QTime t(0, 0, 0, 0);
+ t = t.addSecs(t_sec);
+ t = t.addMSecs(t_msec);
+ QString s_time = t.toString("hh:mm:ss.zzz");
+ ui->relTimeText->setText(s_time);
+
+ quint64 startingTimeStampMsec = m_startingTimeStamp * 1000;
+ QDateTime dt = QDateTime::fromMSecsSinceEpoch(startingTimeStampMsec);
+ dt = dt.addSecs(t_sec);
+ dt = dt.addMSecs(t_msec);
+ QString s_date = dt.toString("yyyyMMdd hh.mm.ss.zzz");
+ ui->absTimeText->setText(s_date);
+}
+
+void SDRdaemonGui::tick()
+{
+ if ((++m_tickCount & 0xf) == 0) {
+ SDRdaemonInput::MsgConfigureSDRdaemonStreamTiming* message = SDRdaemonInput::MsgConfigureSDRdaemonStreamTiming::create();
+ m_sampleSource->getInputMessageQueue()->push(message);
+ }
+}
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemongui.h b/plugins/samplesource/sdrdaemon/sdrdaemongui.h
new file mode 100644
index 000000000..b9216f9b0
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemongui.h
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 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_SDRDAEMONGUI_H
+#define INCLUDE_SDRDAEMONGUI_H
+
+#include
+#include "plugin/plugingui.h"
+
+#include "sdrdaemoninput.h"
+
+class PluginAPI;
+
+namespace Ui {
+ class SDRdaemonGui;
+}
+
+class SDRdaemonGui : public QWidget, public PluginGUI {
+ Q_OBJECT
+
+public:
+ explicit SDRdaemonGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
+ virtual ~SDRdaemonGui();
+ void destroy();
+
+ void setName(const QString& name);
+ QString getName() const;
+
+ void resetToDefaults();
+ virtual qint64 getCenterFrequency() const;
+ virtual void setCenterFrequency(qint64 centerFrequency);
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+ virtual bool handleMessage(const Message& message);
+
+private:
+ Ui::SDRdaemonGui* ui;
+
+ PluginAPI* m_pluginAPI;
+ SDRdaemonInput::Settings m_settings;
+ QTimer m_updateTimer;
+ std::vector m_gains;
+ SampleSource* m_sampleSource;
+ bool m_acquisition;
+ QString m_fileName;
+ int m_sampleRate;
+ quint64 m_centerFrequency;
+ std::time_t m_startingTimeStamp;
+ int m_samplesCount;
+ std::size_t m_tickCount;
+
+ void displaySettings();
+ void displayTime();
+ void sendSettings();
+ void updateHardware();
+ void configureFileName();
+ void updateWithAcquisition();
+ void updateWithStreamData();
+ void updateWithStreamTime();
+
+private slots:
+ void handleSourceMessages();
+ void on_playLoop_toggled(bool checked);
+ void on_play_toggled(bool checked);
+ void on_showFileDialog_clicked(bool checked);
+ void tick();
+};
+
+#endif // INCLUDE_SDRDAEMONGUI_H
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemongui.ui b/plugins/samplesource/sdrdaemon/sdrdaemongui.ui
new file mode 100644
index 000000000..9dcf1e942
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemongui.ui
@@ -0,0 +1,346 @@
+
+
+ SDRdaemonGui
+
+
+
+ 0
+ 0
+ 198
+ 133
+
+
+
+
+ 0
+ 0
+
+
+
+
+ Sans Serif
+ 9
+
+
+
+ BladeRF
+
+
+
+ 3
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 16
+
+
+
+
+ Monospace
+ 20
+
+
+
+ SizeVerCursor
+
+
+ Qt::StrongFocus
+
+
+ Record center frequency in kHz
+
+
+
+ -
+
+
+ kHz
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+ Open file
+
+
+
+
+
+
+ :/preset-load.png:/preset-load.png
+
+
+
+ -
+
+
+ false
+
+
+ File currently opened
+
+
+ ...
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+
+ 8
+
+
+
+ Record sample rate
+
+
+ 0k
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ false
+
+
+ Record absolute time
+
+
+ 20150101 00:00:00.000
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
-
+
+
+ Play in a loop
+
+
+
+
+
+
+ :/playloop.png:/playloop.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+
+ -
+
+
+ Stopped / Play / Pause
+
+
+
+
+
+
+ :/play.png
+ :/pause.png
+ :/stop.png
+ :/stop.png
+ :/play.png
+ :/pause.png
+ :/play.png
+ :/pause.png:/play.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ false
+
+
+ Record time from start
+
+
+ 00:00:00.000
+
+
+
+
+
+
+
+
+
+ ValueDial
+ QWidget
+
+ 1
+
+
+ ButtonSwitch
+ QToolButton
+
+
+
+
+
+
+
+
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemoninput.cpp b/plugins/samplesource/sdrdaemon/sdrdaemoninput.cpp
new file mode 100644
index 000000000..896972e64
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemoninput.cpp
@@ -0,0 +1,290 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+
+#include "util/simpleserializer.h"
+#include "dsp/dspcommands.h"
+#include "dsp/dspengine.h"
+#include "dsp/filesink.h"
+
+#include "sdrdaemongui.h"
+#include "sdrdaemoninput.h"
+#include "sdrdaemonthread.h"
+
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgConfigureSDRdaemon, Message)
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgConfigureSDRdaemonName, Message)
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgConfigureSDRdaemonWork, Message)
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgConfigureSDRdaemonStreamTiming, Message)
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgReportSDRdaemonAcquisition, Message)
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgReportSDRdaemonStreamData, Message)
+MESSAGE_CLASS_DEFINITION(SDRdaemonInput::MsgReportSDRdaemonStreamTiming, Message)
+
+SDRdaemonInput::Settings::Settings() :
+ m_fileName("./test.sdriq")
+{
+}
+
+void SDRdaemonInput::Settings::resetToDefaults()
+{
+ m_fileName = "./test.sdriq";
+}
+
+QByteArray SDRdaemonInput::Settings::serialize() const
+{
+ SimpleSerializer s(1);
+ s.writeString(1, m_fileName);
+ return s.final();
+}
+
+bool SDRdaemonInput::Settings::deserialize(const QByteArray& data)
+{
+ SimpleDeserializer d(data);
+
+ if(!d.isValid()) {
+ resetToDefaults();
+ return false;
+ }
+
+ if(d.getVersion() == 1) {
+ int intval;
+ d.readString(1, &m_fileName, "./test.sdriq");
+ return true;
+ } else {
+ resetToDefaults();
+ return false;
+ }
+}
+
+SDRdaemonInput::SDRdaemonInput(const QTimer& masterTimer) :
+ m_settings(),
+ m_SDRdaemonThread(NULL),
+ m_deviceDescription(),
+ m_fileName("..."),
+ m_sampleRate(0),
+ m_centerFrequency(0),
+ m_startingTimeStamp(0),
+ m_masterTimer(masterTimer)
+{
+}
+
+SDRdaemonInput::~SDRdaemonInput()
+{
+ stop();
+}
+
+void SDRdaemonInput::openFileStream()
+{
+ qDebug() << "SDRdaemonInput::openFileStream: " << m_fileName.toStdString().c_str();
+
+ //stopInput();
+
+ if (m_ifstream.is_open()) {
+ m_ifstream.close();
+ }
+
+ m_ifstream.open(m_fileName.toStdString().c_str(), std::ios::binary);
+ FileSink::Header header;
+ FileSink::readHeader(m_ifstream, header);
+
+ m_sampleRate = header.sampleRate;
+ m_centerFrequency = header.centerFrequency;
+ m_startingTimeStamp = header.startTimeStamp;
+
+ MsgReportSDRdaemonStreamData *report = MsgReportSDRdaemonStreamData::create(m_sampleRate, m_centerFrequency, m_startingTimeStamp); // file stream data
+ getOutputMessageQueueToGUI()->push(report);
+}
+
+bool SDRdaemonInput::init(const Message& message)
+{
+ return false;
+}
+
+bool SDRdaemonInput::start(int device)
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ qDebug() << "SDRdaemonInput::startInput";
+
+ if (m_ifstream.tellg() != 0) {
+ m_ifstream.clear();
+ m_ifstream.seekg(0, std::ios::beg);
+ }
+
+ if(!m_sampleFifo.setSize(96000 * 4)) {
+ qCritical("Could not allocate SampleFifo");
+ return false;
+ }
+
+ //openFileStream();
+
+ if((m_SDRdaemonThread = new SDRdaemonThread(&m_ifstream, &m_sampleFifo)) == NULL) {
+ qFatal("out of memory");
+ stop();
+ return false;
+ }
+
+ m_SDRdaemonThread->setSamplerate(m_sampleRate);
+ m_SDRdaemonThread->connectTimer(m_masterTimer);
+ m_SDRdaemonThread->startWork();
+ m_deviceDescription = "SDRdaemon";
+
+ mutexLocker.unlock();
+ //applySettings(m_generalSettings, m_settings, true);
+ qDebug("SDRdaemonInput::startInput: started");
+
+ MsgReportSDRdaemonAcquisition *report = MsgReportSDRdaemonAcquisition::create(true); // acquisition on
+ getOutputMessageQueueToGUI()->push(report);
+
+ return true;
+}
+
+void SDRdaemonInput::stop()
+{
+ qDebug() << "SDRdaemonInput::stop";
+ QMutexLocker mutexLocker(&m_mutex);
+
+ if(m_SDRdaemonThread != 0)
+ {
+ m_SDRdaemonThread->stopWork();
+ delete m_SDRdaemonThread;
+ m_SDRdaemonThread = 0;
+ }
+
+ m_deviceDescription.clear();
+
+ MsgReportSDRdaemonAcquisition *report = MsgReportSDRdaemonAcquisition::create(false); // acquisition off
+ getOutputMessageQueueToGUI()->push(report);
+}
+
+const QString& SDRdaemonInput::getDeviceDescription() const
+{
+ return m_deviceDescription;
+}
+
+int SDRdaemonInput::getSampleRate() const
+{
+ return m_sampleRate;
+}
+
+quint64 SDRdaemonInput::getCenterFrequency() const
+{
+ return m_centerFrequency;
+}
+
+std::time_t SDRdaemonInput::getStartingTimeStamp() const
+{
+ return m_startingTimeStamp;
+}
+
+bool SDRdaemonInput::handleMessage(const Message& message)
+{
+ if (MsgConfigureSDRdaemonName::match(message))
+ {
+ MsgConfigureSDRdaemonName& conf = (MsgConfigureSDRdaemonName&) message;
+ m_fileName = conf.getFileName();
+ openFileStream();
+ return true;
+ }
+ else if (MsgConfigureSDRdaemonWork::match(message))
+ {
+ MsgConfigureSDRdaemonWork& conf = (MsgConfigureSDRdaemonWork&) message;
+ bool working = conf.isWorking();
+
+ if (m_SDRdaemonThread != 0)
+ {
+ if (working)
+ {
+ m_SDRdaemonThread->startWork();
+ MsgReportSDRdaemonStreamTiming *report =
+ MsgReportSDRdaemonStreamTiming::create(m_SDRdaemonThread->getSamplesCount());
+ getOutputMessageQueueToGUI()->push(report);
+ }
+ else
+ {
+ m_SDRdaemonThread->stopWork();
+ }
+ }
+
+ return true;
+ }
+ else if (MsgConfigureSDRdaemonStreamTiming::match(message))
+ {
+ MsgReportSDRdaemonStreamTiming *report;
+
+ if (m_SDRdaemonThread != 0)
+ {
+ report = MsgReportSDRdaemonStreamTiming::create(m_SDRdaemonThread->getSamplesCount());
+ getOutputMessageQueueToGUI()->push(report);
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool SDRdaemonInput::applySettings(const Settings& settings, bool force)
+{
+ QMutexLocker mutexLocker(&m_mutex);
+ bool wasRunning = false;
+
+ if((m_settings.m_fileName != settings.m_fileName) || force)
+ {
+ m_settings.m_fileName = settings.m_fileName;
+
+ if (m_SDRdaemonThread != 0)
+ {
+ wasRunning = m_SDRdaemonThread->isRunning();
+
+ if (wasRunning)
+ {
+ m_SDRdaemonThread->stopWork();
+ }
+ }
+
+ if (m_ifstream.is_open())
+ {
+ m_ifstream.close();
+ }
+
+ openFileStream();
+
+ if (m_SDRdaemonThread != 0)
+ {
+ m_SDRdaemonThread->setSamplerate(m_sampleRate);
+
+ if (wasRunning)
+ {
+ m_SDRdaemonThread->startWork();
+ }
+ }
+
+ DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency);
+ DSPEngine::instance()->getInputMessageQueue()->push(notif);
+
+ qDebug() << "SDRdaemonInput::applySettings:"
+ << " file name: " << settings.m_fileName.toStdString().c_str()
+ << " center freq: " << m_centerFrequency << " Hz"
+ << " sample rate: " << m_sampleRate
+ << " Unix timestamp: " << m_startingTimeStamp;
+ }
+
+ return true;
+}
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemoninput.h b/plugins/samplesource/sdrdaemon/sdrdaemoninput.h
new file mode 100644
index 000000000..e0c180b20
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemoninput.h
@@ -0,0 +1,213 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 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_SDRDAEMONINPUT_H
+#define INCLUDE_SDRDAEMONINPUT_H
+
+#include "dsp/samplesource.h"
+#include
+#include
+#include
+#include
+#include
+
+class SDRdaemonThread;
+
+class SDRdaemonInput : public SampleSource {
+public:
+ struct Settings {
+ QString m_fileName;
+
+ Settings();
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+ };
+
+ class MsgConfigureSDRdaemon : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const Settings& getSettings() const { return m_settings; }
+
+ static MsgConfigureSDRdaemon* create(const Settings& settings)
+ {
+ return new MsgConfigureSDRdaemon(settings);
+ }
+
+ private:
+ Settings m_settings;
+
+ MsgConfigureSDRdaemon(const Settings& settings) :
+ Message(),
+ m_settings(settings)
+ { }
+ };
+
+ class MsgConfigureSDRdaemonName : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ const QString& getFileName() const { return m_fileName; }
+
+ static MsgConfigureSDRdaemonName* create(const QString& fileName)
+ {
+ return new MsgConfigureSDRdaemonName(fileName);
+ }
+
+ private:
+ QString m_fileName;
+
+ MsgConfigureSDRdaemonName(const QString& fileName) :
+ Message(),
+ m_fileName(fileName)
+ { }
+ };
+
+ class MsgConfigureSDRdaemonWork : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool isWorking() const { return m_working; }
+
+ static MsgConfigureSDRdaemonWork* create(bool working)
+ {
+ return new MsgConfigureSDRdaemonWork(working);
+ }
+
+ private:
+ bool m_working;
+
+ MsgConfigureSDRdaemonWork(bool working) :
+ Message(),
+ m_working(working)
+ { }
+ };
+
+ class MsgConfigureSDRdaemonStreamTiming : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+
+ static MsgConfigureSDRdaemonStreamTiming* create()
+ {
+ return new MsgConfigureSDRdaemonStreamTiming();
+ }
+
+ private:
+
+ MsgConfigureSDRdaemonStreamTiming() :
+ Message()
+ { }
+ };
+
+ class MsgReportSDRdaemonAcquisition : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ bool getAcquisition() const { return m_acquisition; }
+
+ static MsgReportSDRdaemonAcquisition* create(bool acquisition)
+ {
+ return new MsgReportSDRdaemonAcquisition(acquisition);
+ }
+
+ protected:
+ bool m_acquisition;
+
+ MsgReportSDRdaemonAcquisition(bool acquisition) :
+ Message(),
+ m_acquisition(acquisition)
+ { }
+ };
+
+ class MsgReportSDRdaemonStreamData : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ int getSampleRate() const { return m_sampleRate; }
+ quint64 getCenterFrequency() const { return m_centerFrequency; }
+ std::time_t getStartingTimeStamp() const { return m_startingTimeStamp; }
+
+ static MsgReportSDRdaemonStreamData* create(int sampleRate, quint64 centerFrequency, std::time_t startingTimeStamp)
+ {
+ return new MsgReportSDRdaemonStreamData(sampleRate, centerFrequency, startingTimeStamp);
+ }
+
+ protected:
+ int m_sampleRate;
+ quint64 m_centerFrequency;
+ std::time_t m_startingTimeStamp;
+
+ MsgReportSDRdaemonStreamData(int sampleRate, quint64 centerFrequency, std::time_t startingTimeStamp) :
+ Message(),
+ m_sampleRate(sampleRate),
+ m_centerFrequency(centerFrequency),
+ m_startingTimeStamp(startingTimeStamp)
+ { }
+ };
+
+ class MsgReportSDRdaemonStreamTiming : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ std::size_t getSamplesCount() const { return m_samplesCount; }
+
+ static MsgReportSDRdaemonStreamTiming* create(std::size_t samplesCount)
+ {
+ return new MsgReportSDRdaemonStreamTiming(samplesCount);
+ }
+
+ protected:
+ std::size_t m_samplesCount;
+
+ MsgReportSDRdaemonStreamTiming(std::size_t samplesCount) :
+ Message(),
+ m_samplesCount(samplesCount)
+ { }
+ };
+
+ SDRdaemonInput(const QTimer& masterTimer);
+ virtual ~SDRdaemonInput();
+
+ virtual bool init(const Message& message);
+ virtual bool start(int device);
+ virtual void stop();
+
+ virtual const QString& getDeviceDescription() const;
+ virtual int getSampleRate() const;
+ virtual quint64 getCenterFrequency() const;
+ std::time_t getStartingTimeStamp() const;
+
+ virtual bool handleMessage(const Message& message);
+
+private:
+ QMutex m_mutex;
+ Settings m_settings;
+ std::ifstream m_ifstream;
+ SDRdaemonThread* m_SDRdaemonThread;
+ QString m_deviceDescription;
+ QString m_fileName;
+ int m_sampleRate;
+ quint64 m_centerFrequency;
+ std::time_t m_startingTimeStamp;
+ const QTimer& m_masterTimer;
+
+ bool applySettings(const Settings& settings, bool force);
+ void openFileStream();
+};
+
+#endif // INCLUDE_SDRDAEMONINPUT_H
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemonplugin.cpp b/plugins/samplesource/sdrdaemon/sdrdaemonplugin.cpp
new file mode 100644
index 000000000..5bdf64780
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemonplugin.cpp
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////////
+// 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 "sdrdaemongui.h"
+#include "sdrdaemonplugin.h"
+
+const PluginDescriptor SDRdaemonPlugin::m_pluginDescriptor = {
+ QString("File source input"),
+ QString("---"),
+ QString("(c) Edouard Griffiths, F4EXB"),
+ QString("https://github.com/f4exb/sdrangel"),
+ true,
+ QString("https://github.com/f4exb/sdrangel")
+};
+
+const QString SDRdaemonPlugin::m_deviceTypeID = SDRDAEMON_DEVICE_TYPE_ID;
+
+SDRdaemonPlugin::SDRdaemonPlugin(QObject* parent) :
+ QObject(parent)
+{
+}
+
+const PluginDescriptor& SDRdaemonPlugin::getPluginDescriptor() const
+{
+ return m_pluginDescriptor;
+}
+
+void SDRdaemonPlugin::initPlugin(PluginAPI* pluginAPI)
+{
+ m_pluginAPI = pluginAPI;
+ m_pluginAPI->registerSampleSource(m_deviceTypeID, this);
+}
+
+PluginInterface::SampleSourceDevices SDRdaemonPlugin::enumSampleSources()
+{
+ SampleSourceDevices result;
+ int count = 1;
+
+ for(int i = 0; i < count; i++)
+ {
+ QString displayedName(QString("SDRdaemon[%1]").arg(i));
+
+ result.append(SampleSourceDevice(displayedName,
+ m_deviceTypeID,
+ QString::null,
+ i));
+ }
+
+ return result;
+}
+
+PluginGUI* SDRdaemonPlugin::createSampleSourcePluginGUI(const QString& sourceId)
+{
+ if(sourceId == m_deviceTypeID)
+ {
+ SDRdaemonGui* gui = new SDRdaemonGui(m_pluginAPI);
+ m_pluginAPI->setInputGUI(gui);
+ return gui;
+ }
+ else
+ {
+ return NULL;
+ }
+}
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemonplugin.h b/plugins/samplesource/sdrdaemon/sdrdaemonplugin.h
new file mode 100644
index 000000000..3dd77313f
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemonplugin.h
@@ -0,0 +1,47 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 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_SDRDAEMONPLUGIN_H
+#define INCLUDE_SDRDAEMONPLUGIN_H
+
+#include
+#include "plugin/plugininterface.h"
+
+#define SDRDAEMON_DEVICE_TYPE_ID "sdrangel.samplesource.sdrdaemon"
+
+class SDRdaemonPlugin : public QObject, public PluginInterface {
+ Q_OBJECT
+ Q_INTERFACES(PluginInterface)
+ Q_PLUGIN_METADATA(IID SDRDAEMON_DEVICE_TYPE_ID)
+
+public:
+ explicit SDRdaemonPlugin(QObject* parent = NULL);
+
+ const PluginDescriptor& getPluginDescriptor() const;
+ void initPlugin(PluginAPI* pluginAPI);
+
+ virtual SampleSourceDevices enumSampleSources();
+ virtual PluginGUI* createSampleSourcePluginGUI(const QString& sourceId);
+
+ static const QString m_deviceTypeID;
+
+private:
+ static const PluginDescriptor m_pluginDescriptor;
+
+ PluginAPI* m_pluginAPI;
+};
+
+#endif // INCLUDE_SDRDAEMONPLUGIN_H
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemonthread.cpp b/plugins/samplesource/sdrdaemon/sdrdaemonthread.cpp
new file mode 100644
index 000000000..4a261a2f9
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemonthread.cpp
@@ -0,0 +1,153 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2015 Edouard Griffiths, F4EXB //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include "dsp/samplefifo.h"
+#include
+
+#include "sdrdaemonthread.h"
+
+const int SDRdaemonThread::m_rateDivider = 1000/SDRDAEMON_THROTTLE_MS;
+
+SDRdaemonThread::SDRdaemonThread(std::ifstream *samplesStream, SampleFifo* sampleFifo, QObject* parent) :
+ QThread(parent),
+ m_running(false),
+ m_ifstream(samplesStream),
+ m_buf(0),
+ m_bufsize(0),
+ m_chunksize(0),
+ m_sampleFifo(sampleFifo),
+ m_samplesCount(0),
+ m_samplerate(0)
+{
+ assert(m_ifstream != 0);
+}
+
+SDRdaemonThread::~SDRdaemonThread()
+{
+ if (m_running) {
+ stopWork();
+ }
+
+ if (m_buf != 0) {
+ free(m_buf);
+ }
+}
+
+void SDRdaemonThread::startWork()
+{
+ qDebug() << "SDRdaemonThread::startWork: ";
+
+ if (m_ifstream->is_open())
+ {
+ qDebug() << " - file stream open, starting...";
+ m_startWaitMutex.lock();
+ start();
+ while(!m_running)
+ m_startWaiter.wait(&m_startWaitMutex, 100);
+ m_startWaitMutex.unlock();
+ }
+ else
+ {
+ qDebug() << " - file stream closed, not starting.";
+ }
+}
+
+void SDRdaemonThread::stopWork()
+{
+ qDebug() << "SDRdaemonThread::stopWork";
+ m_running = false;
+ wait();
+}
+
+void SDRdaemonThread::setSamplerate(int samplerate)
+{
+ qDebug() << "SDRdaemonThread::setSamplerate:"
+ << " new:" << samplerate
+ << " old:" << m_samplerate;
+
+ if (samplerate != m_samplerate)
+ {
+ if (m_running) {
+ stopWork();
+ }
+
+ m_samplerate = samplerate;
+ m_chunksize = (m_samplerate / m_rateDivider)*4; // TODO: implement FF and slow motion here. 4 corresponds to live. 2 is half speed, 8 is doulbe speed
+ m_bufsize = m_chunksize;
+
+ if (m_buf == 0) {
+ qDebug() << " - Allocate buffer";
+ m_buf = (quint8*) malloc(m_bufsize);
+ } else {
+ qDebug() << " - Re-allocate buffer";
+ m_buf = (quint8*) realloc((void*) m_buf, m_bufsize);
+ }
+
+ qDebug() << " - size: " << m_bufsize
+ << " #samples: " << (m_bufsize/4);
+ }
+
+ //m_samplerate = samplerate;
+}
+
+void SDRdaemonThread::run()
+{
+ int res;
+
+ m_running = true;
+ m_startWaiter.wakeAll();
+
+ while(m_running) // actual work is in the tick() function
+ {
+ sleep(1);
+ }
+
+ m_running = false;
+}
+
+void SDRdaemonThread::connectTimer(const QTimer& timer)
+{
+ qDebug() << "SDRdaemonThread::connectTimer";
+ connect(&timer, SIGNAL(timeout()), this, SLOT(tick()));
+}
+
+void SDRdaemonThread::tick()
+{
+ if (m_running)
+ {
+ // read samples directly feeding the SampleFifo (no callback)
+ m_ifstream->read(reinterpret_cast(m_buf), m_chunksize);
+
+ if (m_ifstream->eof())
+ {
+ m_sampleFifo->write(m_buf, m_ifstream->gcount());
+ // TODO: handle loop playback situation
+ m_ifstream->clear();
+ m_ifstream->seekg(0, std::ios::beg);
+ m_samplesCount = 0;
+ //stopWork();
+ //m_ifstream->close();
+ }
+ else
+ {
+ m_sampleFifo->write(m_buf, m_chunksize);
+ m_samplesCount += m_chunksize / 4;
+ }
+ }
+}
diff --git a/plugins/samplesource/sdrdaemon/sdrdaemonthread.h b/plugins/samplesource/sdrdaemon/sdrdaemonthread.h
new file mode 100644
index 000000000..9d3ff1d3a
--- /dev/null
+++ b/plugins/samplesource/sdrdaemon/sdrdaemonthread.h
@@ -0,0 +1,67 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 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_SDRDAEMONTHREAD_H
+#define INCLUDE_SDRDAEMONTHREAD_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "dsp/samplefifo.h"
+#include "dsp/inthalfbandfilter.h"
+
+#define SDRDAEMON_THROTTLE_MS 50
+
+class SDRdaemonThread : public QThread {
+ Q_OBJECT
+
+public:
+ SDRdaemonThread(std::ifstream *samplesStream, SampleFifo* sampleFifo, QObject* parent = NULL);
+ ~SDRdaemonThread();
+
+ void startWork();
+ void stopWork();
+ void setSamplerate(int samplerate);
+ bool isRunning() const { return m_running; }
+ std::size_t getSamplesCount() const { return m_samplesCount; }
+
+ void connectTimer(const QTimer& timer);
+
+private:
+ QMutex m_startWaitMutex;
+ QWaitCondition m_startWaiter;
+ bool m_running;
+
+ std::ifstream* m_ifstream;
+ quint8 *m_buf;
+ std::size_t m_bufsize;
+ std::size_t m_chunksize;
+ SampleFifo* m_sampleFifo;
+ std::size_t m_samplesCount;
+
+ int m_samplerate;
+ static const int m_rateDivider;
+
+ void run();
+private slots:
+ void tick();
+};
+
+#endif // INCLUDE_SDRDAEMONTHREAD_H