1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-02-03 09:44:01 -05:00

Local output plugin and fixes

This commit is contained in:
f4exb 2019-05-10 23:38:52 +02:00
parent ba4c8d7a68
commit 8029194c02
42 changed files with 2386 additions and 43 deletions

View File

@ -57,7 +57,8 @@ LocalSource::LocalSource(DeviceAPI *deviceAPI) :
m_centerFrequency(0),
m_frequencyOffset(0),
m_sampleRate(48000),
m_deviceSampleRate(48000)
m_deviceSampleRate(48000),
m_settingsMutex(QMutex::Recursive)
{
setObjectName(m_channelId);
@ -82,27 +83,35 @@ LocalSource::~LocalSource()
void LocalSource::pull(Sample& sample)
{
sample = m_localSamples[m_localSamplesIndex + m_localSamplesIndexOffset];
if (m_localSamplesIndex < m_chunkSize - 1)
if (m_localSampleSourceFifo)
{
m_localSamplesIndex++;
QMutexLocker mutexLocker(&m_settingsMutex);
sample = m_localSamples[m_localSamplesIndex + m_localSamplesIndexOffset];
if (m_localSamplesIndex < m_chunkSize - 1)
{
m_localSamplesIndex++;
}
else
{
m_localSamplesIndex = 0;
if (m_localSamplesIndexOffset == 0) {
m_localSamplesIndexOffset = m_chunkSize;
} else {
m_localSamplesIndexOffset = 0;
}
emit pullSamples(m_chunkSize);
}
}
else
{
m_localSamplesIndex = 0;
if (m_localSamplesIndexOffset == 0) {
m_localSamplesIndexOffset = m_chunkSize;
} else {
m_localSamplesIndexOffset = 0;
}
emit pullSamples(m_chunkSize);
sample = Sample{0, 0};
}
}
void LocalSource::processSamples(unsigned int offset)
void LocalSource::processSamples(int offset)
{
if (m_localSampleSourceFifo)
{
@ -152,7 +161,7 @@ void LocalSource::start()
connect(m_sinkThread,
SIGNAL(samplesAvailable(int)),
this,
SLOT(pprocessSamples(int)),
SLOT(processSamples(int)),
Qt::QueuedConnection);
m_sinkThread->startStop(true);
@ -178,14 +187,25 @@ bool LocalSource::handleMessage(const Message& cmd)
if (UpChannelizer::MsgChannelizerNotification::match(cmd))
{
UpChannelizer::MsgChannelizerNotification& notif = (UpChannelizer::MsgChannelizerNotification&) cmd;
int sampleRate = notif.getSampleRate();
qDebug() << "LocalSource::handleMessage: MsgChannelizerNotification:"
<< " channelSampleRate: " << notif.getSampleRate()
<< " channelSampleRate: " << sampleRate
<< " offsetFrequency: " << notif.getFrequencyOffset();
if (notif.getSampleRate() > 0)
if (sampleRate > 0)
{
setSampleRate(notif.getSampleRate());
if (m_localSampleSourceFifo)
{
QMutexLocker mutexLocker(&m_settingsMutex);
m_localSampleSourceFifo->resize(sampleRate);
m_chunkSize = sampleRate / 8;
m_localSamplesIndex = 0;
m_localSamplesIndexOffset = 0;
m_localSamples.resize(2*m_chunkSize);
}
setSampleRate(sampleRate);
}
return true;

View File

@ -177,6 +177,8 @@ private:
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
QMutex m_settingsMutex;
void applySettings(const LocalSourceSettings& settings, bool force = false);
DeviceSampleSink *getLocalDevice(uint32_t index);
void propagateSampleRateAndFrequency(uint32_t index);
@ -187,7 +189,7 @@ private:
private slots:
void networkManagerFinished(QNetworkReply *reply);
void processSamples(unsigned int offset);
void processSamples(int offset);
};
#endif /* INCLUDE_LOCALSOURCE_H_ */

View File

@ -130,7 +130,7 @@ LocalSourceGUI::LocalSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
m_settings.setChannelMarker(&m_channelMarker);
m_deviceUISet->registerRxChannelInstance(LocalSource::m_channelIdURI, this);
m_deviceUISet->registerTxChannelInstance(LocalSource::m_channelIdURI, this);
m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this);

View File

@ -49,4 +49,5 @@ if (BUILD_DEBIAN)
endif (BUILD_DEBIAN)
add_subdirectory(filesink)
add_subdirectory(localoutput)

View File

@ -0,0 +1,50 @@
project(localoutput)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(localoutput_SOURCES
localoutputgui.cpp
localoutput.cpp
localoutputplugin.cpp
localoutputsettings.cpp
)
set(localoutput_HEADERS
localoutputgui.h
localoutput.h
localoutputplugin.h
localoutputsettings.h
)
set(localoutput_FORMS
localoutputgui.ui
)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
qt5_wrap_ui(localoutput_FORMS_HEADERS ${localoutput_FORMS})
add_library(outputlocal SHARED
${localoutput_SOURCES}
${localoutput_HEADERS_MOC}
${localoutput_FORMS_HEADERS}
)
target_link_libraries(outputlocal
${QT_LIBRARIES}
sdrbase
sdrgui
swagger
)
target_link_libraries(outputlocal Qt5::Core Qt5::Widgets)
install(TARGETS outputlocal DESTINATION lib/plugins/samplesink)

View File

@ -0,0 +1,397 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 <QDebug>
#include <QNetworkReply>
#include <QBuffer>
#include "SWGDeviceSettings.h"
#include "SWGDeviceState.h"
#include "SWGDeviceReport.h"
#include "SWGLocalOutputReport.h"
#include "util/simpleserializer.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "device/deviceapi.h"
#include "localoutput.h"
MESSAGE_CLASS_DEFINITION(LocalOutput::MsgConfigureLocalOutput, Message)
MESSAGE_CLASS_DEFINITION(LocalOutput::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(LocalOutput::MsgReportSampleRateAndFrequency, Message)
LocalOutput::LocalOutput(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_settings(),
m_deviceDescription("LocalOutput")
{
m_sampleSourceFifo.resize(96000 * 4);
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
}
LocalOutput::~LocalOutput()
{
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
stop();
}
void LocalOutput::destroy()
{
delete this;
}
void LocalOutput::init()
{
applySettings(m_settings, true);
}
bool LocalOutput::start()
{
qDebug() << "LocalOutput::start";
return true;
}
void LocalOutput::stop()
{
qDebug() << "LocalOutput::stop";
}
QByteArray LocalOutput::serialize() const
{
return m_settings.serialize();
}
bool LocalOutput::deserialize(const QByteArray& data)
{
bool success = true;
if (!m_settings.deserialize(data))
{
m_settings.resetToDefaults();
success = false;
}
MsgConfigureLocalOutput* message = MsgConfigureLocalOutput::create(m_settings, true);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureLocalOutput* messageToGUI = MsgConfigureLocalOutput::create(m_settings, true);
m_guiMessageQueue->push(messageToGUI);
}
return success;
}
void LocalOutput::setMessageQueueToGUI(MessageQueue *queue)
{
m_guiMessageQueue = queue;
}
const QString& LocalOutput::getDeviceDescription() const
{
return m_deviceDescription;
}
int LocalOutput::getSampleRate() const
{
return m_sampleRate;
}
void LocalOutput::setSampleRate(int sampleRate)
{
m_sampleRate = sampleRate;
DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); // Frequency in Hz for the DSP engine
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
if (getMessageQueueToGUI())
{
MsgReportSampleRateAndFrequency *msg = MsgReportSampleRateAndFrequency::create(m_sampleRate, m_centerFrequency);
getMessageQueueToGUI()->push(msg);
}
}
quint64 LocalOutput::getCenterFrequency() const
{
return m_centerFrequency;
}
void LocalOutput::setCenterFrequency(qint64 centerFrequency)
{
m_centerFrequency = centerFrequency;
DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); // Frequency in Hz for the DSP engine
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
if (getMessageQueueToGUI())
{
MsgReportSampleRateAndFrequency *msg = MsgReportSampleRateAndFrequency::create(m_sampleRate, m_centerFrequency);
getMessageQueueToGUI()->push(msg);
}
}
bool LocalOutput::handleMessage(const Message& message)
{
if (DSPSignalNotification::match(message))
{
return false;
}
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "LocalOutput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
if (cmd.getStartStop())
{
if (m_deviceAPI->initDeviceEngine())
{
m_deviceAPI->startDeviceEngine();
}
}
else
{
m_deviceAPI->stopDeviceEngine();
}
if (m_settings.m_useReverseAPI) {
webapiReverseSendStartStop(cmd.getStartStop());
}
return true;
}
else if (MsgConfigureLocalOutput::match(message))
{
qDebug() << "LocalOutput::handleMessage:" << message.getIdentifier();
MsgConfigureLocalOutput& conf = (MsgConfigureLocalOutput&) message;
applySettings(conf.getSettings(), conf.getForce());
return true;
}
else
{
return false;
}
}
void LocalOutput::applySettings(const LocalOutputSettings& settings, bool force)
{
QMutexLocker mutexLocker(&m_mutex);
std::ostringstream os;
QString remoteAddress;
QList<QString> reverseAPIKeys;
if (settings.m_useReverseAPI)
{
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
(m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex);
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
m_remoteAddress = remoteAddress;
qDebug() << "LocalOutput::applySettings: "
<< " m_remoteAddress: " << m_remoteAddress;
}
int LocalOutput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
int LocalOutput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgStartStop *msgToGUI = MsgStartStop::create(run);
m_guiMessageQueue->push(msgToGUI);
}
return 200;
}
int LocalOutput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setLocalOutputSettings(new SWGSDRangel::SWGLocalOutputSettings());
response.getLocalOutputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int LocalOutput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) errorMessage;
LocalOutputSettings settings = m_settings;
if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getLocalOutputSettings()->getUseReverseApi() != 0;
}
if (deviceSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getLocalOutputSettings()->getReverseApiAddress();
}
if (deviceSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getLocalOutputSettings()->getReverseApiPort();
}
if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIDeviceIndex = response.getLocalOutputSettings()->getReverseApiDeviceIndex();
}
MsgConfigureLocalOutput *msg = MsgConfigureLocalOutput::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureLocalOutput *msgToGUI = MsgConfigureLocalOutput::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatDeviceSettings(response, settings);
return 200;
}
void LocalOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const LocalOutputSettings& settings)
{
response.getLocalOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getLocalOutputSettings()->getReverseApiAddress()) {
*response.getLocalOutputSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getLocalOutputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getLocalOutputSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getLocalOutputSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
}
int LocalOutput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage)
{
(void) errorMessage;
response.setLocalOutputReport(new SWGSDRangel::SWGLocalOutputReport());
response.getLocalOutputReport()->init();
webapiFormatDeviceReport(response);
return 200;
}
void LocalOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response)
{
response.getLocalOutputReport()->setCenterFrequency(m_centerFrequency);
response.getLocalOutputReport()->setSampleRate(m_sampleRate);
}
void LocalOutput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const LocalOutputSettings& settings, bool force)
{
(void) deviceSettingsKeys;
(void) force;
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
swgDeviceSettings->setDirection(1); // single Tx
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
swgDeviceSettings->setDeviceHwType(new QString("LocalOutput"));
swgDeviceSettings->setLocalOutputSettings(new SWGSDRangel::SWGLocalOutputSettings());
// transfer data that has been modified. When force is on transfer all data except reverse API data
QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex);
m_networkRequest.setUrl(QUrl(deviceSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer=new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgDeviceSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
delete swgDeviceSettings;
}
void LocalOutput::webapiReverseSendStartStop(bool start)
{
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
swgDeviceSettings->setDirection(0); // single Rx
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
swgDeviceSettings->setDeviceHwType(new QString("LocalInput"));
QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex);
m_networkRequest.setUrl(QUrl(deviceSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer=new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgDeviceSettings->asJson().toUtf8());
buffer->seek(0);
if (start) {
m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
} else {
m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
}
}
void LocalOutput::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "LocalOutput::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
return;
}
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("LocalOutput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}

View File

@ -0,0 +1,172 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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_LOCALOUTPUT_H
#define INCLUDE_LOCALOUTPUT_H
#include <ctime>
#include <iostream>
#include <stdint.h>
#include <QString>
#include <QByteArray>
#include <QTimer>
#include <QNetworkRequest>
#include "dsp/devicesamplesink.h"
#include "localoutputsettings.h"
class QNetworkAccessManager;
class QNetworkReply;
class DeviceAPI;
class FileRecord;
class LocalOutput : public DeviceSampleSink {
Q_OBJECT
public:
class MsgConfigureLocalOutput : public Message {
MESSAGE_CLASS_DECLARATION
public:
const LocalOutputSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureLocalOutput* create(const LocalOutputSettings& settings, bool force = false)
{
return new MsgConfigureLocalOutput(settings, force);
}
private:
LocalOutputSettings m_settings;
bool m_force;
MsgConfigureLocalOutput(const LocalOutputSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
class MsgReportSampleRateAndFrequency : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static MsgReportSampleRateAndFrequency* create(int sampleRate, qint64 centerFrequency) {
return new MsgReportSampleRateAndFrequency(sampleRate, centerFrequency);
}
protected:
int m_sampleRate;
qint64 m_centerFrequency;
MsgReportSampleRateAndFrequency(int sampleRate, qint64 centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
LocalOutput(DeviceAPI *deviceAPI);
virtual ~LocalOutput();
virtual void destroy();
virtual void init();
virtual bool start();
virtual void stop();
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual void setMessageQueueToGUI(MessageQueue *queue);
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual void setSampleRate(int sampleRate);
virtual quint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
std::time_t getStartingTimeStamp() const;
virtual bool handleMessage(const Message& message);
virtual int webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage);
virtual int webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
private:
DeviceAPI *m_deviceAPI;
QMutex m_mutex;
LocalOutputSettings m_settings;
qint64 m_centerFrequency;
int m_sampleRate;
QString m_remoteAddress;
QString m_deviceDescription;
FileRecord *m_fileSink; //!< File sink to record device I/Q output
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void applySettings(const LocalOutputSettings& settings, bool force = false);
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const LocalOutputSettings& settings);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const LocalOutputSettings& settings, bool force);
void webapiReverseSendStartStop(bool start);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif // INCLUDE_LOCALOUTPUT_H

View File

@ -0,0 +1,329 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 <stdint.h>
#include <sstream>
#include <iostream>
#include <cassert>
#include <QDebug>
#include <QMessageBox>
#include <QTime>
#include <QDateTime>
#include <QString>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonParseError>
#include <QJsonObject>
#include "ui_localoutputgui.h"
#include "gui/colormapper.h"
#include "gui/glspectrum.h"
#include "gui/crightclickenabler.h"
#include "gui/basicdevicesettingsdialog.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "mainwindow.h"
#include "util/simpleserializer.h"
#include "device/deviceapi.h"
#include "device/deviceuiset.h"
#include "localoutputgui.h"
LocalOutputGui::LocalOutputGui(DeviceUISet *deviceUISet, QWidget* parent) :
QWidget(parent),
ui(new Ui::LocalOutputGui),
m_deviceUISet(deviceUISet),
m_settings(),
m_sampleSink(0),
m_acquisition(false),
m_streamSampleRate(0),
m_streamCenterFrequency(0),
m_lastEngineState(DeviceAPI::StNotStarted),
m_samplesCount(0),
m_tickCount(0),
m_doApplySettings(true),
m_forceSettings(true)
{
m_paletteGreenText.setColor(QPalette::WindowText, Qt::green);
m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white);
ui->setupUi(this);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->centerFrequency->setValueRange(7, 0, 9999999U);
ui->centerFrequencyHz->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->centerFrequencyHz->setValueRange(3, 0, 999U);
CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
displaySettings();
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(500);
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
m_sampleSink = (LocalOutput*) m_deviceUISet->m_deviceAPI->getSampleSink();
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
m_sampleSink->setMessageQueueToGUI(&m_inputMessageQueue);
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
m_forceSettings = true;
sendSettings();
}
LocalOutputGui::~LocalOutputGui()
{
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
delete ui;
}
void LocalOutputGui::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void LocalOutputGui::destroy()
{
delete this;
}
void LocalOutputGui::setName(const QString& name)
{
setObjectName(name);
}
QString LocalOutputGui::getName() const
{
return objectName();
}
void LocalOutputGui::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
m_forceSettings = true;
sendSettings();
}
QByteArray LocalOutputGui::serialize() const
{
return m_settings.serialize();
}
bool LocalOutputGui::deserialize(const QByteArray& data)
{
qDebug("LocalOutputGui::deserialize");
if (m_settings.deserialize(data))
{
displaySettings();
m_forceSettings = true;
sendSettings();
return true;
}
else
{
return false;
}
}
qint64 LocalOutputGui::getCenterFrequency() const
{
return m_streamCenterFrequency;
}
void LocalOutputGui::setCenterFrequency(qint64 centerFrequency)
{
(void) centerFrequency;
}
bool LocalOutputGui::handleMessage(const Message& message)
{
if (LocalOutput::MsgConfigureLocalOutput::match(message))
{
const LocalOutput::MsgConfigureLocalOutput& cfg = (LocalOutput::MsgConfigureLocalOutput&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (LocalOutput::MsgStartStop::match(message))
{
LocalOutput::MsgStartStop& notif = (LocalOutput::MsgStartStop&) message;
blockApplySettings(true);
ui->startStop->setChecked(notif.getStartStop());
blockApplySettings(false);
return true;
}
else if (LocalOutput::MsgReportSampleRateAndFrequency::match(message))
{
LocalOutput::MsgReportSampleRateAndFrequency& notif = (LocalOutput::MsgReportSampleRateAndFrequency&) message;
m_streamSampleRate = notif.getSampleRate();
m_streamCenterFrequency = notif.getCenterFrequency();
updateSampleRateAndFrequency();
return true;
}
else
{
return false;
}
}
void LocalOutputGui::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
//qDebug("LocalOutputGui::handleInputMessages: message: %s", message->getIdentifier());
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
if (notif->getSampleRate() != m_streamSampleRate) {
m_streamSampleRate = notif->getSampleRate();
}
m_streamCenterFrequency = notif->getCenterFrequency();
qDebug("LocalOutputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency());
updateSampleRateAndFrequency();
DSPSignalNotification *fwd = new DSPSignalNotification(*notif);
m_sampleSink->getInputMessageQueue()->push(fwd);
delete message;
}
else
{
if (handleMessage(*message))
{
delete message;
}
}
}
}
void LocalOutputGui::updateSampleRateAndFrequency()
{
m_deviceUISet->getSpectrum()->setSampleRate(m_streamSampleRate);
m_deviceUISet->getSpectrum()->setCenterFrequency(m_streamCenterFrequency);
ui->deviceRateText->setText(tr("%1k").arg((float)m_streamSampleRate / 1000));
blockApplySettings(true);
ui->centerFrequency->setValue(m_streamCenterFrequency / 1000);
ui->centerFrequencyHz->setValue(m_streamCenterFrequency % 1000);
blockApplySettings(false);
}
void LocalOutputGui::displaySettings()
{
blockApplySettings(true);
ui->centerFrequency->setValue(m_streamCenterFrequency / 1000);
ui->centerFrequencyHz->setValue(m_streamCenterFrequency % 1000);
ui->deviceRateText->setText(tr("%1k").arg(m_streamSampleRate / 1000.0));
blockApplySettings(false);
}
void LocalOutputGui::sendSettings()
{
if(!m_updateTimer.isActive())
m_updateTimer.start(100);
}
void LocalOutputGui::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
LocalOutput::MsgStartStop *message = LocalOutput::MsgStartStop::create(checked);
m_sampleSink->getInputMessageQueue()->push(message);
}
}
void LocalOutputGui::updateHardware()
{
if (m_doApplySettings)
{
qDebug() << "LocalOutputGui::updateHardware";
LocalOutput::MsgConfigureLocalOutput* message =
LocalOutput::MsgConfigureLocalOutput::create(m_settings, m_forceSettings);
m_sampleSink->getInputMessageQueue()->push(message);
m_forceSettings = false;
m_updateTimer.stop();
}
}
void LocalOutputGui::updateStatus()
{
int state = m_deviceUISet->m_deviceAPI->state();
if(m_lastEngineState != state)
{
switch(state)
{
case DeviceAPI::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case DeviceAPI::StIdle:
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case DeviceAPI::StRunning:
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case DeviceAPI::StError:
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceAPI->errorMessage());
break;
default:
break;
}
m_lastEngineState = state;
}
}
void LocalOutputGui::openDeviceSettingsDialog(const QPoint& p)
{
BasicDeviceSettingsDialog dialog(this);
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
dialog.move(p);
dialog.exec();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
sendSettings();
}

View File

@ -0,0 +1,97 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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_LOCALOUTPUTGUI_H
#define INCLUDE_LOCALOUTPUTGUI_H
#include <QTimer>
#include <QWidget>
#include <QNetworkRequest>
#include "plugin/plugininstancegui.h"
#include "util/messagequeue.h"
#include "localoutput.h"
class DeviceUISet;
class QNetworkAccessManager;
class QNetworkReply;
class QJsonObject;
namespace Ui {
class LocalOutputGui;
}
class LocalOutputGui : public QWidget, public PluginInstanceGUI {
Q_OBJECT
public:
explicit LocalOutputGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
virtual ~LocalOutputGui();
virtual void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual qint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message);
private:
Ui::LocalOutputGui* ui;
DeviceUISet* m_deviceUISet;
LocalOutputSettings m_settings; //!< current settings
LocalOutput* m_sampleSink;
bool m_acquisition;
int m_streamSampleRate; //!< Sample rate of received stream
quint64 m_streamCenterFrequency; //!< Center frequency of received stream
QTimer m_updateTimer;
QTimer m_statusTimer;
int m_lastEngineState;
MessageQueue m_inputMessageQueue;
int m_samplesCount;
std::size_t m_tickCount;
bool m_doApplySettings;
bool m_forceSettings;
QPalette m_paletteGreenText;
QPalette m_paletteWhiteText;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void blockApplySettings(bool block);
void displaySettings();
void sendSettings();
void updateSampleRateAndFrequency();
private slots:
void handleInputMessages();
void on_startStop_toggled(bool checked);
void updateHardware();
void updateStatus();
void openDeviceSettingsDialog(const QPoint& p);
};
#endif // INCLUDE_LOCALOUTPUTGUI_H

View File

@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LocalOutputGui</class>
<widget class="QWidget" name="LocalOutputGui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<height>80</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>360</width>
<height>80</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Local Output</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_freq">
<property name="topMargin">
<number>4</number>
</property>
<item>
<layout class="QVBoxLayout" name="deviceUILayout">
<item>
<layout class="QHBoxLayout" name="deviceButtonsLayout">
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/play.png</normaloff>
<normalon>:/stop.png</normalon>:/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="record">
<property name="toolTip">
<string>Toggle record I/Q samples from device</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/record_off.png</normaloff>:/record_off.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="deviceRateLayout">
<item>
<widget class="QLabel" name="deviceRateText">
<property name="toolTip">
<string>I/Q sample rate kS/s</string>
</property>
<property name="text">
<string>00000k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="freqLeftSpacer">
<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="enabled">
<bool>false</bool>
</property>
<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>Liberation Mono</family>
<pointsize>20</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>ForbiddenCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Remote center frequency kHz</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="hertzLayout">
<item>
<widget class="ValueDial" name="centerFrequencyHz" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>ForbiddenCursor</cursorShape>
</property>
<property name="toolTip">
<string>Remote center frequency sub kHz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="freqUnits">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string> Hz</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_address">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="padLayout">
<item>
<spacer name="verticalPadSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,113 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 <QtPlugin>
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#ifdef SERVER_MODE
#include "localoutput.h"
#else
#include "localoutputgui.h"
#endif
#include "localoutputplugin.h"
const PluginDescriptor LocalOutputPlugin::m_pluginDescriptor = {
QString("Local device output"),
QString("4.8.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
const QString LocalOutputPlugin::m_hardwareID = "LocalOutput";
const QString LocalOutputPlugin::m_deviceTypeID = LOCALOUTPUT_DEVICE_TYPE_ID;
LocalOutputPlugin::LocalOutputPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& LocalOutputPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void LocalOutputPlugin::initPlugin(PluginAPI* pluginAPI)
{
pluginAPI->registerSampleSink(m_deviceTypeID, this);
}
PluginInterface::SamplingDevices LocalOutputPlugin::enumSampleSinks()
{
SamplingDevices result;
result.append(SamplingDevice(
"LocalOutput",
m_hardwareID,
m_deviceTypeID,
QString::null,
0,
PluginInterface::SamplingDevice::BuiltInDevice,
PluginInterface::SamplingDevice::StreamSingleTx,
1,
0));
return result;
}
#ifdef SERVER_MODE
PluginInstanceGUI* LocalOutputPlugin::createSampleSinkPluginInstanceGUI(
const QString& sinkId __attribute((unused)),
QWidget **widget __attribute((unused)),
DeviceUISet *deviceUISet __attribute((unused)))
{
return 0;
}
#else
PluginInstanceGUI* LocalOutputPlugin::createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
if(sinkId == m_deviceTypeID)
{
LocalOutputGui* gui = new LocalOutputGui(deviceUISet);
*widget = gui;
return gui;
}
else
{
return 0;
}
}
#endif
DeviceSampleSink *LocalOutputPlugin::createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceAPI *deviceAPI)
{
if (sinkId == m_deviceTypeID)
{
LocalOutput* output = new LocalOutput(deviceAPI);
return output;
}
else
{
return 0;
}
}

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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_LOCALOUTPUTPLUGIN_H
#define INCLUDE_LOCALOUTPUTPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
#define LOCALOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesource.localoutput"
class PluginAPI;
class LocalOutputPlugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID LOCALOUTPUT_DEVICE_TYPE_ID)
public:
explicit LocalOutputPlugin(QObject* parent = nullptr);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual SamplingDevices enumSampleSinks();
virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet);
virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceAPI *deviceAPI);
static const QString m_hardwareID;
static const QString m_deviceTypeID;
private:
static const PluginDescriptor m_pluginDescriptor;
};
#endif // INCLUDE_LOCALOUTPUTPLUGIN_H

View File

@ -0,0 +1,80 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 "util/simpleserializer.h"
#include "localoutputsettings.h"
LocalOutputSettings::LocalOutputSettings()
{
resetToDefaults();
}
void LocalOutputSettings::resetToDefaults()
{
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
}
QByteArray LocalOutputSettings::serialize() const
{
SimpleSerializer s(1);
s.writeString(4, m_reverseAPIAddress);
s.writeU32(5, m_reverseAPIPort);
s.writeU32(6, m_reverseAPIDeviceIndex);
return s.final();
}
bool LocalOutputSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
quint32 uintval;
d.readString(4, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(5, &uintval, 0);
if ((uintval > 1023) && (uintval < 65535)) {
m_reverseAPIPort = uintval;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(6, &uintval, 0);
m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval;
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 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 //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_
#define PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_
#include <QByteArray>
#include <QString>
struct LocalOutputSettings {
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
LocalOutputSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ */

View File

@ -26,7 +26,7 @@ set(remoteoutput_HEADERS
remoteoutput.h
remoteoutputplugin.h
remoteoutputsettings.h
remoteoutputthreads.h
remoteoutputthread.h
udpsinkfec.h
udpsinkfecworker.h
)
@ -39,16 +39,16 @@ if (BUILD_DEBIAN)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${LIBCM256CCSRC}/..
)
else (BUILD_DEBIAN)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/devices
${CM256CC_INCLUDE_DIR}
${CM256CC_INCLUDE_DIR}
)
endif (BUILD_DEBIAN)
@ -78,7 +78,7 @@ target_link_libraries(outputremote
sdrbase
sdrgui
swagger
${CM256CC_LIBRARIES}
${CM256CC_LIBRARIES}
)
endif (BUILD_DEBIAN)

View File

@ -43,8 +43,7 @@ MESSAGE_CLASS_DEFINITION(LocalInput::MsgReportSampleRateAndFrequency, Message)
LocalInput::LocalInput(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_settings(),
m_deviceDescription("LocalInput"),
m_startingTimeStamp(0)
m_deviceDescription("LocalInput")
{
m_sampleFifo.setSize(96000 * 4);
@ -160,11 +159,6 @@ void LocalInput::setCenterFrequency(qint64 centerFrequency)
}
}
std::time_t LocalInput::getStartingTimeStamp() const
{
return m_startingTimeStamp;
}
bool LocalInput::handleMessage(const Message& message)
{
if (DSPSignalNotification::match(message))

View File

@ -15,8 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_REMOTEINPUT_H
#define INCLUDE_REMOTEINPUT_H
#ifndef INCLUDE_LOCALINPUT_H
#define INCLUDE_LOCALINPUT_H
#include <ctime>
#include <iostream>
@ -139,7 +139,6 @@ public:
virtual void setSampleRate(int sampleRate);
virtual quint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
std::time_t getStartingTimeStamp() const;
virtual bool handleMessage(const Message& message);
@ -174,7 +173,6 @@ private:
int m_sampleRate;
QString m_remoteAddress;
QString m_deviceDescription;
std::time_t m_startingTimeStamp;
FileRecord *m_fileSink; //!< File sink to record device I/Q output
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
@ -189,4 +187,4 @@ private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif // INCLUDE_REMOTEINPUT_H
#endif // INCLUDE_LOCALINPUT_H

View File

@ -15,8 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_REMOTEINPUTGUI_H
#define INCLUDE_REMOTEINPUTGUI_H
#ifndef INCLUDE_LOCALINPUTGUI_H
#define INCLUDE_LOCALINPUTGUI_H
#include <QTimer>
#include <QWidget>
@ -124,4 +124,4 @@ private slots:
void openDeviceSettingsDialog(const QPoint& p);
};
#endif // INCLUDE_REMOTEINPUTGUI_H
#endif // INCLUDE_LOCALINPUTGUI_H

View File

@ -5,6 +5,7 @@ add_subdirectory(modnfm)
add_subdirectory(modssb)
add_subdirectory(modwfm)
add_subdirectory(udpsource)
add_subdirectory(localsource)
find_package(CM256cc)
if(CM256CC_FOUND)

View File

@ -0,0 +1,46 @@
project(localsource)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PLUGIN_PREFIX "../../../plugins/channeltx/localsource")
set(localsource_SOURCES
${PLUGIN_PREFIX}/localsource.cpp
${PLUGIN_PREFIX}/localsourcethread.cpp
${PLUGIN_PREFIX}/localsourceplugin.cpp
${PLUGIN_PREFIX}/localsourcesettings.cpp
)
set(localsource_HEADERS
${PLUGIN_PREFIX}/localsource.h
${PLUGIN_PREFIX}/localsourcethread.h
${PLUGIN_PREFIX}/localsourceplugin.h
${PLUGIN_PREFIX}/localsourcesettings.h
)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CM256CC_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
#include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
add_library(localsourcesrv SHARED
${localsource_SOURCES}
${localsource_HEADERS_MOC}
)
target_link_libraries(localsourcesrv
${QT_LIBRARIES}
${CM256CC_LIBRARIES}
sdrbase
swagger
)
target_link_libraries(localsourcesrv Qt5::Core Qt5::Network)
install(TARGETS localsourcesrv DESTINATION lib/pluginssrv/channeltx)

View File

@ -48,3 +48,4 @@ if (BUILD_DEBIAN)
endif (BUILD_DEBIAN)
add_subdirectory(filesink)
add_subdirectory(localoutput)

View File

@ -0,0 +1,41 @@
project(localoutput)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PLUGIN_PREFIX "../../../plugins/samplesink/localoutput")
set(localoutput_SOURCES
${PLUGIN_PREFIX}/localoutput.cpp
${PLUGIN_PREFIX}/localoutputplugin.cpp
${PLUGIN_PREFIX}/localoutputsettings.cpp
)
set(localoutput_HEADERS
${PLUGIN_PREFIX}/localoutput.h
${PLUGIN_PREFIX}/localoutputplugin.h
${PLUGIN_PREFIX}/localoutputsettings.h
)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
add_library(outputlocalsrv SHARED
${localoutput_SOURCES}
${localoutput_HEADERS_MOC}
)
target_link_libraries(outputlocalsrv
${QT_LIBRARIES}
sdrbase
swagger
)
target_link_libraries(outputlocalsrv Qt5::Core)
install(TARGETS outputlocalsrv DESTINATION lib/pluginssrv/samplesink)

View File

@ -374,6 +374,7 @@ double UpChannelizer::setFilterChain(const std::vector<unsigned int>& stageIndex
// filters are described from lower to upper level but the chain is constructed the other way round
std::vector<unsigned int>::const_reverse_iterator rit = stageIndexes.rbegin();
double ofs = 0.0, ofs_stage = 0.25;
Sample s;
// Each index is a base 3 number with 0 = low, 1 = center, 2 = high
// Functions at upper level will convert a number to base 3 to describe the filter chain. Common converting
@ -383,15 +384,18 @@ double UpChannelizer::setFilterChain(const std::vector<unsigned int>& stageIndex
if (*rit == 0)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
m_stageSamples.push_back(s);
ofs -= ofs_stage;
}
else if (*rit == 1)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
m_stageSamples.push_back(s);
}
else if (*rit == 2)
{
m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
m_stageSamples.push_back(s);
ofs += ofs_stage;
}

View File

@ -38,6 +38,8 @@ const QString PluginManager::m_remoteInputDeviceTypeID = "sdrangel.samplesource.
const QString PluginManager::m_fileSourceHardwareID = "FileSource";
const QString PluginManager::m_fileSourceDeviceTypeID = "sdrangel.samplesource.filesource";
const QString PluginManager::m_localOutputHardwareID = "LocalOutput";
const QString PluginManager::m_localOutputDeviceTypeID = "sdrangel.samplesource.localoutput";
const QString PluginManager::m_remoteOutputHardwareID = "RemoteOutput";
const QString PluginManager::m_remoteOutputDeviceTypeID = "sdrangel.samplesink.remoteoutput";
const QString PluginManager::m_fileSinkHardwareID = "FileSink";

View File

@ -110,6 +110,8 @@ private:
static const QString m_fileSourceDeviceTypeID; //!< FileSource source plugin ID
// "Local" sample sink device IDs
static const QString m_localOutputHardwareID; //!< Local output hardware ID
static const QString m_localOutputDeviceTypeID; //!< Local output plugin ID
static const QString m_remoteOutputHardwareID; //!< Remote output hardware ID
static const QString m_remoteOutputDeviceTypeID; //!< Remote output plugin ID
static const QString m_fileSinkHardwareID; //!< FileSource source hardware ID

View File

@ -21,6 +21,7 @@
<file>webapi/doc/swagger/include/HackRF.yaml</file>
<file>webapi/doc/swagger/include/LimeSdr.yaml</file>
<file>webapi/doc/swagger/include/LocalInput.yaml</file>
<file>webapi/doc/swagger/include/LocalOutput.yaml</file>
<file>webapi/doc/swagger/include/NFMDemod.yaml</file>
<file>webapi/doc/swagger/include/NFMMod.yaml</file>
<file>webapi/doc/swagger/include/Perseus.yaml</file>

View File

@ -2165,6 +2165,9 @@ margin-bottom: 20px;
"localInputReport" : {
"$ref" : "#/definitions/LocalInputReport"
},
"localOutputReport" : {
"$ref" : "#/definitions/LocalOutputReport"
},
"perseusReport" : {
"$ref" : "#/definitions/PerseusReport"
},
@ -2299,6 +2302,9 @@ margin-bottom: 20px;
"localInputSettings" : {
"$ref" : "#/definitions/LocalInputSettings"
},
"localOutputSettings" : {
"$ref" : "#/definitions/LocalOutputSettings"
},
"perseusSettings" : {
"$ref" : "#/definitions/PerseusSettings"
},
@ -3364,6 +3370,36 @@ margin-bottom: 20px;
}
},
"description" : "LocalInput"
};
defs.LocalOutputReport = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "uint64"
},
"sampleRate" : {
"type" : "integer"
}
},
"description" : "LocalOutput"
};
defs.LocalOutputSettings = {
"properties" : {
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
}
},
"description" : "LocalOutput"
};
defs.LocalSinkSettings = {
"properties" : {
@ -24964,7 +25000,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2019-05-10T00:00:57.798+02:00
Generated 2019-05-10T14:58:45.508+02:00
</div>
</div>
</div>

View File

@ -0,0 +1,21 @@
LocalOutputSettings:
description: LocalOutput
properties:
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
LocalOutputReport:
description: LocalOutput
properties:
centerFrequency:
type: integer
format: uint64
sampleRate:
type: integer

View File

@ -1808,6 +1808,8 @@ definitions:
$ref: "/doc/swagger/include/LimeSdr.yaml#/LimeSdrOutputSettings"
localInputSettings:
$ref: "/doc/swagger/include/LocalInput.yaml#/LocalInputSettings"
localOutputSettings:
$ref: "/doc/swagger/include/LocalOutput.yaml#/LocalOutputSettings"
perseusSettings:
$ref: "/doc/swagger/include/Perseus.yaml#/PerseusSettings"
plutoSdrInputSettings:
@ -1863,6 +1865,8 @@ definitions:
$ref: "/doc/swagger/include/LimeSdr.yaml#/LimeSdrOutputReport"
localInputReport:
$ref: "/doc/swagger/include/LocalInput.yaml#/LocalInputReport"
localOutputReport:
$ref: "/doc/swagger/include/LocalOutput.yaml#/LocalOutputReport"
perseusReport:
$ref: "/doc/swagger/include/Perseus.yaml#/PerseusReport"
plutoSdrInputReport:

View File

@ -2166,6 +2166,21 @@ bool WebAPIRequestMapper::validateDeviceSettings(
return false;
}
}
else if ((*deviceHwType == "LocalOutput") && (deviceSettings.getDirection() == 1))
{
if (jsonObject.contains("localOutputSettings") && jsonObject["localOutputSettings"].isObject())
{
QJsonObject localOutputSettingsJsonObject = jsonObject["localOutputSettings"].toObject();
deviceSettingsKeys = localOutputSettingsJsonObject.keys();
deviceSettings.setLocalOutputSettings(new SWGSDRangel::SWGLocalOutputSettings());
deviceSettings.getLocalOutputSettings()->fromJsonObject(localOutputSettingsJsonObject);
return true;
}
else
{
return false;
}
}
else
{
return false;

View File

@ -0,0 +1,21 @@
LocalOutputSettings:
description: LocalOutput
properties:
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
LocalOutputReport:
description: LocalOutput
properties:
centerFrequency:
type: integer
format: uint64
sampleRate:
type: integer

View File

@ -1808,6 +1808,8 @@ definitions:
$ref: "http://localhost:8081/api/swagger/include/LimeSdr.yaml#/LimeSdrOutputSettings"
localInputSettings:
$ref: "http://localhost:8081/api/swagger/include/LocalInput.yaml#/LocalInputSettings"
localOutputSettings:
$ref: "http://localhost:8081/api/swagger/include/LocalOutput.yaml#/LocalOutputSettings"
perseusSettings:
$ref: "http://localhost:8081/api/swagger/include/Perseus.yaml#/PerseusSettings"
plutoSdrInputSettings:
@ -1863,6 +1865,8 @@ definitions:
$ref: "http://localhost:8081/api/swagger/include/LimeSdr.yaml#/LimeSdrOutputReport"
localInputReport:
$ref: "http://localhost:8081/api/swagger/include/LocalInput.yaml#/LocalInputReport"
localOutputReport:
$ref: "http://localhost:8081/api/swagger/include/LocalOutput.yaml#/LocalOutputReport"
perseusReport:
$ref: "http://localhost:8081/api/swagger/include/Perseus.yaml#/PerseusReport"
plutoSdrInputReport:

View File

@ -2165,6 +2165,9 @@ margin-bottom: 20px;
"localInputReport" : {
"$ref" : "#/definitions/LocalInputReport"
},
"localOutputReport" : {
"$ref" : "#/definitions/LocalOutputReport"
},
"perseusReport" : {
"$ref" : "#/definitions/PerseusReport"
},
@ -2299,6 +2302,9 @@ margin-bottom: 20px;
"localInputSettings" : {
"$ref" : "#/definitions/LocalInputSettings"
},
"localOutputSettings" : {
"$ref" : "#/definitions/LocalOutputSettings"
},
"perseusSettings" : {
"$ref" : "#/definitions/PerseusSettings"
},
@ -3364,6 +3370,36 @@ margin-bottom: 20px;
}
},
"description" : "LocalInput"
};
defs.LocalOutputReport = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "uint64"
},
"sampleRate" : {
"type" : "integer"
}
},
"description" : "LocalOutput"
};
defs.LocalOutputSettings = {
"properties" : {
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
}
},
"description" : "LocalOutput"
};
defs.LocalSinkSettings = {
"properties" : {
@ -24964,7 +25000,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2019-05-10T00:00:57.798+02:00
Generated 2019-05-10T14:58:45.508+02:00
</div>
</div>
</div>

View File

@ -48,6 +48,8 @@ SWGDeviceReport::SWGDeviceReport() {
m_lime_sdr_output_report_isSet = false;
local_input_report = nullptr;
m_local_input_report_isSet = false;
local_output_report = nullptr;
m_local_output_report_isSet = false;
perseus_report = nullptr;
m_perseus_report_isSet = false;
pluto_sdr_input_report = nullptr;
@ -98,6 +100,8 @@ SWGDeviceReport::init() {
m_lime_sdr_output_report_isSet = false;
local_input_report = new SWGLocalInputReport();
m_local_input_report_isSet = false;
local_output_report = new SWGLocalOutputReport();
m_local_output_report_isSet = false;
perseus_report = new SWGPerseusReport();
m_perseus_report_isSet = false;
pluto_sdr_input_report = new SWGPlutoSdrInputReport();
@ -152,6 +156,9 @@ SWGDeviceReport::cleanup() {
if(local_input_report != nullptr) {
delete local_input_report;
}
if(local_output_report != nullptr) {
delete local_output_report;
}
if(perseus_report != nullptr) {
delete perseus_report;
}
@ -218,6 +225,8 @@ SWGDeviceReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&local_input_report, pJson["localInputReport"], "SWGLocalInputReport", "SWGLocalInputReport");
::SWGSDRangel::setValue(&local_output_report, pJson["localOutputReport"], "SWGLocalOutputReport", "SWGLocalOutputReport");
::SWGSDRangel::setValue(&perseus_report, pJson["perseusReport"], "SWGPerseusReport", "SWGPerseusReport");
::SWGSDRangel::setValue(&pluto_sdr_input_report, pJson["plutoSdrInputReport"], "SWGPlutoSdrInputReport", "SWGPlutoSdrInputReport");
@ -286,6 +295,9 @@ SWGDeviceReport::asJsonObject() {
if((local_input_report != nullptr) && (local_input_report->isSet())){
toJsonValue(QString("localInputReport"), local_input_report, obj, QString("SWGLocalInputReport"));
}
if((local_output_report != nullptr) && (local_output_report->isSet())){
toJsonValue(QString("localOutputReport"), local_output_report, obj, QString("SWGLocalOutputReport"));
}
if((perseus_report != nullptr) && (perseus_report->isSet())){
toJsonValue(QString("perseusReport"), perseus_report, obj, QString("SWGPerseusReport"));
}
@ -423,6 +435,16 @@ SWGDeviceReport::setLocalInputReport(SWGLocalInputReport* local_input_report) {
this->m_local_input_report_isSet = true;
}
SWGLocalOutputReport*
SWGDeviceReport::getLocalOutputReport() {
return local_output_report;
}
void
SWGDeviceReport::setLocalOutputReport(SWGLocalOutputReport* local_output_report) {
this->local_output_report = local_output_report;
this->m_local_output_report_isSet = true;
}
SWGPerseusReport*
SWGDeviceReport::getPerseusReport() {
return perseus_report;
@ -548,6 +570,7 @@ SWGDeviceReport::isSet(){
if(lime_sdr_input_report != nullptr && lime_sdr_input_report->isSet()){ isObjectUpdated = true; break;}
if(lime_sdr_output_report != nullptr && lime_sdr_output_report->isSet()){ isObjectUpdated = true; break;}
if(local_input_report != nullptr && local_input_report->isSet()){ isObjectUpdated = true; break;}
if(local_output_report != nullptr && local_output_report->isSet()){ isObjectUpdated = true; break;}
if(perseus_report != nullptr && perseus_report->isSet()){ isObjectUpdated = true; break;}
if(pluto_sdr_input_report != nullptr && pluto_sdr_input_report->isSet()){ isObjectUpdated = true; break;}
if(pluto_sdr_output_report != nullptr && pluto_sdr_output_report->isSet()){ isObjectUpdated = true; break;}

View File

@ -30,6 +30,7 @@
#include "SWGLimeSdrInputReport.h"
#include "SWGLimeSdrOutputReport.h"
#include "SWGLocalInputReport.h"
#include "SWGLocalOutputReport.h"
#include "SWGPerseusReport.h"
#include "SWGPlutoSdrInputReport.h"
#include "SWGPlutoSdrOutputReport.h"
@ -90,6 +91,9 @@ public:
SWGLocalInputReport* getLocalInputReport();
void setLocalInputReport(SWGLocalInputReport* local_input_report);
SWGLocalOutputReport* getLocalOutputReport();
void setLocalOutputReport(SWGLocalOutputReport* local_output_report);
SWGPerseusReport* getPerseusReport();
void setPerseusReport(SWGPerseusReport* perseus_report);
@ -157,6 +161,9 @@ private:
SWGLocalInputReport* local_input_report;
bool m_local_input_report_isSet;
SWGLocalOutputReport* local_output_report;
bool m_local_output_report_isSet;
SWGPerseusReport* perseus_report;
bool m_perseus_report_isSet;

View File

@ -62,6 +62,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
m_lime_sdr_output_settings_isSet = false;
local_input_settings = nullptr;
m_local_input_settings_isSet = false;
local_output_settings = nullptr;
m_local_output_settings_isSet = false;
perseus_settings = nullptr;
m_perseus_settings_isSet = false;
pluto_sdr_input_settings = nullptr;
@ -128,6 +130,8 @@ SWGDeviceSettings::init() {
m_lime_sdr_output_settings_isSet = false;
local_input_settings = new SWGLocalInputSettings();
m_local_input_settings_isSet = false;
local_output_settings = new SWGLocalOutputSettings();
m_local_output_settings_isSet = false;
perseus_settings = new SWGPerseusSettings();
m_perseus_settings_isSet = false;
pluto_sdr_input_settings = new SWGPlutoSdrInputSettings();
@ -203,6 +207,9 @@ SWGDeviceSettings::cleanup() {
if(local_input_settings != nullptr) {
delete local_input_settings;
}
if(local_output_settings != nullptr) {
delete local_output_settings;
}
if(perseus_settings != nullptr) {
delete perseus_settings;
}
@ -286,6 +293,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&local_input_settings, pJson["localInputSettings"], "SWGLocalInputSettings", "SWGLocalInputSettings");
::SWGSDRangel::setValue(&local_output_settings, pJson["localOutputSettings"], "SWGLocalOutputSettings", "SWGLocalOutputSettings");
::SWGSDRangel::setValue(&perseus_settings, pJson["perseusSettings"], "SWGPerseusSettings", "SWGPerseusSettings");
::SWGSDRangel::setValue(&pluto_sdr_input_settings, pJson["plutoSdrInputSettings"], "SWGPlutoSdrInputSettings", "SWGPlutoSdrInputSettings");
@ -377,6 +386,9 @@ SWGDeviceSettings::asJsonObject() {
if((local_input_settings != nullptr) && (local_input_settings->isSet())){
toJsonValue(QString("localInputSettings"), local_input_settings, obj, QString("SWGLocalInputSettings"));
}
if((local_output_settings != nullptr) && (local_output_settings->isSet())){
toJsonValue(QString("localOutputSettings"), local_output_settings, obj, QString("SWGLocalOutputSettings"));
}
if((perseus_settings != nullptr) && (perseus_settings->isSet())){
toJsonValue(QString("perseusSettings"), perseus_settings, obj, QString("SWGPerseusSettings"));
}
@ -587,6 +599,16 @@ SWGDeviceSettings::setLocalInputSettings(SWGLocalInputSettings* local_input_sett
this->m_local_input_settings_isSet = true;
}
SWGLocalOutputSettings*
SWGDeviceSettings::getLocalOutputSettings() {
return local_output_settings;
}
void
SWGDeviceSettings::setLocalOutputSettings(SWGLocalOutputSettings* local_output_settings) {
this->local_output_settings = local_output_settings;
this->m_local_output_settings_isSet = true;
}
SWGPerseusSettings*
SWGDeviceSettings::getPerseusSettings() {
return perseus_settings;
@ -729,6 +751,7 @@ SWGDeviceSettings::isSet(){
if(lime_sdr_input_settings != nullptr && lime_sdr_input_settings->isSet()){ isObjectUpdated = true; break;}
if(lime_sdr_output_settings != nullptr && lime_sdr_output_settings->isSet()){ isObjectUpdated = true; break;}
if(local_input_settings != nullptr && local_input_settings->isSet()){ isObjectUpdated = true; break;}
if(local_output_settings != nullptr && local_output_settings->isSet()){ isObjectUpdated = true; break;}
if(perseus_settings != nullptr && perseus_settings->isSet()){ isObjectUpdated = true; break;}
if(pluto_sdr_input_settings != nullptr && pluto_sdr_input_settings->isSet()){ isObjectUpdated = true; break;}
if(pluto_sdr_output_settings != nullptr && pluto_sdr_output_settings->isSet()){ isObjectUpdated = true; break;}

View File

@ -36,6 +36,7 @@
#include "SWGLimeSdrInputSettings.h"
#include "SWGLimeSdrOutputSettings.h"
#include "SWGLocalInputSettings.h"
#include "SWGLocalOutputSettings.h"
#include "SWGPerseusSettings.h"
#include "SWGPlutoSdrInputSettings.h"
#include "SWGPlutoSdrOutputSettings.h"
@ -119,6 +120,9 @@ public:
SWGLocalInputSettings* getLocalInputSettings();
void setLocalInputSettings(SWGLocalInputSettings* local_input_settings);
SWGLocalOutputSettings* getLocalOutputSettings();
void setLocalOutputSettings(SWGLocalOutputSettings* local_output_settings);
SWGPerseusSettings* getPerseusSettings();
void setPerseusSettings(SWGPerseusSettings* perseus_settings);
@ -210,6 +214,9 @@ private:
SWGLocalInputSettings* local_input_settings;
bool m_local_input_settings_isSet;
SWGLocalOutputSettings* local_output_settings;
bool m_local_output_settings_isSet;
SWGPerseusSettings* perseus_settings;
bool m_perseus_settings_isSet;

View File

@ -0,0 +1,127 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.8.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGLocalOutputReport.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGLocalOutputReport::SWGLocalOutputReport(QString* json) {
init();
this->fromJson(*json);
}
SWGLocalOutputReport::SWGLocalOutputReport() {
center_frequency = 0;
m_center_frequency_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
}
SWGLocalOutputReport::~SWGLocalOutputReport() {
this->cleanup();
}
void
SWGLocalOutputReport::init() {
center_frequency = 0;
m_center_frequency_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
}
void
SWGLocalOutputReport::cleanup() {
}
SWGLocalOutputReport*
SWGLocalOutputReport::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGLocalOutputReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&center_frequency, pJson["centerFrequency"], "qint32", "");
::SWGSDRangel::setValue(&sample_rate, pJson["sampleRate"], "qint32", "");
}
QString
SWGLocalOutputReport::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGLocalOutputReport::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_center_frequency_isSet){
obj->insert("centerFrequency", QJsonValue(center_frequency));
}
if(m_sample_rate_isSet){
obj->insert("sampleRate", QJsonValue(sample_rate));
}
return obj;
}
qint32
SWGLocalOutputReport::getCenterFrequency() {
return center_frequency;
}
void
SWGLocalOutputReport::setCenterFrequency(qint32 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32
SWGLocalOutputReport::getSampleRate() {
return sample_rate;
}
void
SWGLocalOutputReport::setSampleRate(qint32 sample_rate) {
this->sample_rate = sample_rate;
this->m_sample_rate_isSet = true;
}
bool
SWGLocalOutputReport::isSet(){
bool isObjectUpdated = false;
do{
if(m_center_frequency_isSet){ isObjectUpdated = true; break;}
if(m_sample_rate_isSet){ isObjectUpdated = true; break;}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,64 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.8.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGLocalOutputReport.h
*
* LocalOutput
*/
#ifndef SWGLocalOutputReport_H_
#define SWGLocalOutputReport_H_
#include <QJsonObject>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGLocalOutputReport: public SWGObject {
public:
SWGLocalOutputReport();
SWGLocalOutputReport(QString* json);
virtual ~SWGLocalOutputReport();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGLocalOutputReport* fromJson(QString &jsonString) override;
qint32 getCenterFrequency();
void setCenterFrequency(qint32 center_frequency);
qint32 getSampleRate();
void setSampleRate(qint32 sample_rate);
virtual bool isSet() override;
private:
qint32 center_frequency;
bool m_center_frequency_isSet;
qint32 sample_rate;
bool m_sample_rate_isSet;
};
}
#endif /* SWGLocalOutputReport_H_ */

View File

@ -0,0 +1,171 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.8.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGLocalOutputSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGLocalOutputSettings::SWGLocalOutputSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGLocalOutputSettings::SWGLocalOutputSettings() {
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = nullptr;
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
}
SWGLocalOutputSettings::~SWGLocalOutputSettings() {
this->cleanup();
}
void
SWGLocalOutputSettings::init() {
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = new QString("");
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
}
void
SWGLocalOutputSettings::cleanup() {
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGLocalOutputSettings*
SWGLocalOutputSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGLocalOutputSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
}
QString
SWGLocalOutputSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGLocalOutputSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
}
if(m_reverse_api_port_isSet){
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
}
if(m_reverse_api_device_index_isSet){
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
}
return obj;
}
qint32
SWGLocalOutputSettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGLocalOutputSettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGLocalOutputSettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGLocalOutputSettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGLocalOutputSettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGLocalOutputSettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGLocalOutputSettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGLocalOutputSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
bool
SWGLocalOutputSettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_use_reverse_api_isSet){ isObjectUpdated = true; break;}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ isObjectUpdated = true; break;}
if(m_reverse_api_port_isSet){ isObjectUpdated = true; break;}
if(m_reverse_api_device_index_isSet){ isObjectUpdated = true; break;}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,77 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.8.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGLocalOutputSettings.h
*
* LocalOutput
*/
#ifndef SWGLocalOutputSettings_H_
#define SWGLocalOutputSettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGLocalOutputSettings: public SWGObject {
public:
SWGLocalOutputSettings();
SWGLocalOutputSettings(QString* json);
virtual ~SWGLocalOutputSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGLocalOutputSettings* fromJson(QString &jsonString) override;
qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api);
QString* getReverseApiAddress();
void setReverseApiAddress(QString* reverse_api_address);
qint32 getReverseApiPort();
void setReverseApiPort(qint32 reverse_api_port);
qint32 getReverseApiDeviceIndex();
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
virtual bool isSet() override;
private:
qint32 use_reverse_api;
bool m_use_reverse_api_isSet;
QString* reverse_api_address;
bool m_reverse_api_address_isSet;
qint32 reverse_api_port;
bool m_reverse_api_port_isSet;
qint32 reverse_api_device_index;
bool m_reverse_api_device_index_isSet;
};
}
#endif /* SWGLocalOutputSettings_H_ */

View File

@ -81,6 +81,8 @@
#include "SWGLimeSdrOutputSettings.h"
#include "SWGLocalInputReport.h"
#include "SWGLocalInputSettings.h"
#include "SWGLocalOutputReport.h"
#include "SWGLocalOutputSettings.h"
#include "SWGLocalSinkSettings.h"
#include "SWGLocalSourceSettings.h"
#include "SWGLocationInformation.h"
@ -348,6 +350,12 @@ namespace SWGSDRangel {
if(QString("SWGLocalInputSettings").compare(type) == 0) {
return new SWGLocalInputSettings();
}
if(QString("SWGLocalOutputReport").compare(type) == 0) {
return new SWGLocalOutputReport();
}
if(QString("SWGLocalOutputSettings").compare(type) == 0) {
return new SWGLocalOutputSettings();
}
if(QString("SWGLocalSinkSettings").compare(type) == 0) {
return new SWGLocalSinkSettings();
}