major rewrite and changes... far too many to put into individual commits

This commit is contained in:
Christian Daniel 2013-09-23 21:31:54 +02:00
parent 69673c7a64
commit 9fd7152f13
56 changed files with 1456 additions and 295 deletions

View File

@ -3,7 +3,9 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
project(sdrangelove)
set(CMAKE_BUILD_TYPE "Release")
#set(CMAKE_BUILD_TYPE "Release")
#set(CMAKE_BUILD_TYPE "ReleaseWithDebInfo")
set(CMAKE_BUILD_TYPE "Debug")
set(QT_USE_QTOPENGL TRUE)
set(CMAKE_AUTOMOC ON)
@ -24,12 +26,12 @@ find_package(FFTW3F)
add_definitions(${QT_DEFINITIONS})
if(MSVC)
foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin_${OUTPUTCONFIG})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin_${OUTPUTCONFIG})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin_${OUTPUTCONFIG})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin_${OUTPUTCONFIG})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin_${OUTPUTCONFIG})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin_${OUTPUTCONFIG})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
endif()
##############################################################################
@ -61,6 +63,8 @@ set(sdrbase_SOURCES
sdrbase/gui/aboutdialog.cpp
sdrbase/gui/addpresetdialog.cpp
sdrbase/gui/buttonswitch.cpp
sdrbase/gui/channelwindow.cpp
sdrbase/gui/glscope.cpp
sdrbase/gui/glspectrum.cpp
sdrbase/gui/glspectrumgui.cpp
@ -68,6 +72,7 @@ set(sdrbase_SOURCES
sdrbase/gui/pluginsdialog.cpp
sdrbase/gui/preferencesdialog.cpp
sdrbase/gui/presetitem.cpp
sdrbase/gui/rollupwidget.cpp
sdrbase/gui/scale.cpp
sdrbase/gui/scaleengine.cpp
sdrbase/gui/scopewindow.cpp
@ -119,6 +124,8 @@ set(sdrbase_HEADERS
include-gpl/gui/aboutdialog.h
include-gpl/gui/addpresetdialog.h
include-gpl/gui/buttonswitch.h
include-gpl/gui/channelwindow.h
include-gpl/gui/glscope.h
include-gpl/gui/glspectrum.h
include-gpl/gui/glspectrumgui.h
@ -127,6 +134,7 @@ set(sdrbase_HEADERS
include-gpl/gui/pluginsdialog.h
include-gpl/gui/preferencesdialog.h
include-gpl/gui/presetitem.h
include/gui/rollupwidget.h
include-gpl/gui/scale.h
include-gpl/gui/scaleengine.h
include-gpl/gui/scopewindow.h

View File

@ -0,0 +1,19 @@
#ifndef INCLUDE_BUTTONSWITCH_H
#define INCLUDE_BUTTONSWITCH_H
#include <QToolButton>
class ButtonSwitch : public QToolButton {
Q_OBJECT
public:
ButtonSwitch(QWidget* parent = NULL);
private slots:
void onToggled(bool checked);
private:
QPalette m_originalPalette;
};
#endif // INCLUDE_BUTTONSWITCH_H

View File

@ -0,0 +1,25 @@
#ifndef INCLUDE_CHANNELWINDOW_H
#define INCLUDE_CHANNELWINDOW_H
#include <QScrollArea>
class QBoxLayout;
class QSpacerItem;
class RollupWidget;
class ChannelWindow : public QScrollArea {
Q_OBJECT
public:
ChannelWindow(QWidget* parent = NULL);
void addRollupWidget(QWidget* rollupWidget);
protected:
QWidget* m_container;
QBoxLayout* m_layout;
void resizeEvent(QResizeEvent* event);
};
#endif // INCLUDE_CHANNELWINDOW_H

View File

@ -37,7 +37,8 @@ public:
ModeIQ,
ModeMagLinPha,
ModeMagdBPha,
ModeDerived12
ModeDerived12,
ModeCyclostationary
};
GLScope(QWidget* parent = NULL);

View File

@ -39,7 +39,7 @@ public:
void setPowerRange(Real powerRange);
void setDisplayWaterfall(bool display);
void setInvertedWaterfall(bool inv);
void setDisplayLiveSpectrum(bool display);
void setDisplayMaxHold(bool display);
void setDisplayHistogram(bool display);
void addChannelMarker(ChannelMarker* channelMarker);
@ -84,9 +84,8 @@ private:
bool m_invertedWaterfall;
std::vector<Real> m_liveSpectrum;
bool m_displayLiveSpectrum;
bool m_liveSpectrumChanged;
std::vector<Real> m_maxHold;
bool m_displayMaxHold;
Real m_waterfallShare;

View File

@ -40,7 +40,7 @@ private:
Real m_powerRange;
bool m_displayWaterfall;
bool m_invertedWaterfall;
bool m_displayLiveSpectrum;
bool m_displayMaxHold;
bool m_displayHistogram;
void applySettings();
@ -53,7 +53,7 @@ private slots:
void on_decay_valueChanged(int value);
void on_waterfall_toggled(bool checked);
void on_histogram_toggled(bool checked);
void on_liveSpectrum_toggled(bool checked);
void on_maxHold_toggled(bool checked);
};
#endif // INCLUDE_GLSPECTRUMGUI_H

View File

@ -53,7 +53,8 @@ public:
MessageQueue* getMessageQueue() { return m_messageQueue; }
void addDemodCreateAction(QAction* action);
void addChannelCreateAction(QAction* action);
void addChannelRollup(QWidget* widget);
void addViewAction(QAction* action);
void addChannelMarker(ChannelMarker* channelMarker);
@ -67,7 +68,7 @@ private:
PItem
};
Ui::MainWindow *ui;
Ui::MainWindow* ui;
AudioDeviceInfo* m_audioDeviceInfo;

View File

@ -37,8 +37,10 @@ public:
const Plugins& getPlugins() const { return m_plugins; }
void registerDemodulator(const QString& demodName, PluginInterface* plugin, QAction* action);
void registerDemodulatorInstance(const QString& demodName, PluginGUI* pluginGUI);
void registerChannel(const QString& channelName, PluginInterface* plugin, QAction* action);
void registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI);
void addChannelRollup(QWidget* pluginGUI);
void removeChannelInstance(PluginGUI* pluginGUI);
void registerSampleSource(const QString& sourceName, PluginInterface* plugin);
@ -54,33 +56,30 @@ public:
int selectSampleSource(int index);
int selectSampleSource(const QString& source);
private slots:
void demodInstanceDestroyed(QObject* object);
private:
struct DemodRegistration {
QString m_demodName;
struct ChannelRegistration {
QString m_channelName;
PluginInterface* m_plugin;
DemodRegistration(const QString& demodName, PluginInterface* plugin) :
m_demodName(demodName),
ChannelRegistration(const QString& channelName, PluginInterface* plugin) :
m_channelName(channelName),
m_plugin(plugin)
{ }
};
typedef QList<DemodRegistration> DemodRegistrations;
typedef QList<ChannelRegistration> ChannelRegistrations;
struct DemodInstanceRegistration {
QString m_demodName;
struct ChannelInstanceRegistration {
QString m_channelName;
PluginGUI* m_gui;
DemodInstanceRegistration() :
m_demodName(),
ChannelInstanceRegistration() :
m_channelName(),
m_gui(NULL)
{ }
DemodInstanceRegistration(const QString& demodName, PluginGUI* pluginGUI) :
m_demodName(demodName),
ChannelInstanceRegistration(const QString& channelName, PluginGUI* pluginGUI) :
m_channelName(channelName),
m_gui(pluginGUI)
{ }
};
typedef QList<DemodInstanceRegistration> DemodInstanceRegistrations;
typedef QList<ChannelInstanceRegistration> ChannelInstanceRegistrations;
struct SampleSourceRegistration {
QString m_sourceName;
@ -112,8 +111,8 @@ private:
DSPEngine* m_dspEngine;
Plugins m_plugins;
DemodRegistrations m_demodRegistrations;
DemodInstanceRegistrations m_demodInstanceRegistrations;
ChannelRegistrations m_channelRegistrations;
ChannelInstanceRegistrations m_channelInstanceRegistrations;
SampleSourceRegistrations m_sampleSourceRegistrations;
SampleSourceDevices m_sampleSourceDevices;
@ -121,7 +120,7 @@ private:
PluginGUI* m_sampleSourceInstance;
void loadPlugins(const QDir& dir);
void renameDemodInstances();
void renameChannelInstances();
};
static inline bool operator<(const PluginManager::Plugin& a, const PluginManager::Plugin& b)

View File

@ -7,16 +7,16 @@
class Preset {
public:
struct DemodConfig {
QString m_demod;
struct ChannelConfig {
QString m_channel;
QByteArray m_config;
DemodConfig(const QString& demod, const QByteArray& config) :
m_demod(demod),
ChannelConfig(const QString& channel, const QByteArray& config) :
m_channel(channel),
m_config(config)
{ }
};
typedef QList<DemodConfig> DemodConfigs;
typedef QList<ChannelConfig> ChannelConfigs;
Preset();
@ -49,10 +49,10 @@ public:
void setScopeConfig(const QByteArray& data) { m_scopeConfig = data; }
const QByteArray& getScopeConfig() const { return m_scopeConfig; }
void clearDemods() { m_demodConfigs.clear(); }
void addDemod(const QString& demod, const QByteArray& config) { m_demodConfigs.append(DemodConfig(demod, config)); }
int getDemodCount() const { return m_demodConfigs.count(); }
const DemodConfig& getDemodConfig(int index) const { return m_demodConfigs.at(index); }
void clearChannels() { m_channelConfigs.clear(); }
void addChannel(const QString& channel, const QByteArray& config) { m_channelConfigs.append(ChannelConfig(channel, config)); }
int getChannelCount() const { return m_channelConfigs.count(); }
const ChannelConfig& getChannelConfig(int index) const { return m_channelConfigs.at(index); }
void setSourceConfig(const QString& source, const QByteArray& generalConfig, const QByteArray& config)
{
@ -86,8 +86,8 @@ protected:
QByteArray m_sourceGeneralConfig;
QByteArray m_sourceConfig;
// demodulators and configurations
DemodConfigs m_demodConfigs;
// channels and configurations
ChannelConfigs m_channelConfigs;
// screen and dock layout
QByteArray m_layout;

View File

@ -0,0 +1,28 @@
#ifndef INCLUDE_DEMODWIDGET_H
#define INCLUDE_DEMODWIDGET_H
#include <QWidget>
class RollupWidget : public QWidget {
Q_OBJECT
public:
RollupWidget(QWidget* parent = NULL);
void addRollup(QWidget* rollup);
protected:
//QWidgetList m_rollups;
int arrangeRollups();
void paintEvent(QPaintEvent*);
int paintRollup(QWidget* rollup, int pos, QPainter* p, bool last, const QColor& frame);
void resizeEvent(QResizeEvent* size);
void mousePressEvent(QMouseEvent* event);
bool eventFilter(QObject* object, QEvent* event);
};
#endif // INCLUDE_DEMODWIDGET_H

View File

@ -25,10 +25,13 @@ public:
// MainWindow access
QDockWidget* createMainWindowDock(Qt::DockWidgetArea dockWidgetArea, const QString& title);
MessageQueue* getMainWindowMessageQueue();
void setInputGUI(QWidget* inputGUI);
// Demodulator stuff
void registerDemodulator(const QString& demodName, PluginInterface* plugin, QAction* action);
void registerDemodulatorInstance(const QString& demodName, PluginGUI* pluginGUI);
// Channel stuff
void registerChannel(const QString& channelName, PluginInterface* plugin, QAction* action);
void registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI);
void addChannelRollup(QWidget* pluginGUI);
void removeChannelInstance(PluginGUI* pluginGUI);
void addChannelMarker(ChannelMarker* channelMarker);
void removeChannelMarker(ChannelMarker* channelMarker);

View File

@ -6,14 +6,12 @@
class Message;
class SDRANGELOVE_API PluginGUI : public QWidget {
Q_OBJECT
class SDRANGELOVE_API PluginGUI {
public:
PluginGUI(QWidget* parent = NULL);
PluginGUI() { };
virtual void destroy() = 0;
virtual void setWidgetName(const QString& name);
virtual void setName(const QString& name) = 0;
virtual void resetToDefaults() = 0;

View File

@ -37,7 +37,7 @@ public:
virtual const PluginDescriptor& getPluginDescriptor() const = 0;
virtual void initPlugin(PluginAPI* pluginAPI) = 0;
virtual PluginGUI* createDemod(const QString& demodName) { return NULL; }
virtual PluginGUI* createChannel(const QString& channelName) { return NULL; }
virtual SampleSourceDevices enumSampleSources() { return SampleSourceDevices(); }
virtual PluginGUI* createSampleSource(const QString& sourceName, const QByteArray& address) { return NULL; }

View File

@ -19,37 +19,73 @@
#include <QTextCodec>
#include <QProxyStyle>
#include <QStyleFactory>
#include <QFontDatabase>
#include "mainwindow.h"
static int runQtApplication(int argc, char* argv[])
{
QApplication a(argc, argv);
/*QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));*/
/*
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
*/
QCoreApplication::setOrganizationName("osmocom");
QCoreApplication::setApplicationName("SDRangelove");
//QApplication::setStyle(new QProxyStyle());
#if 0
#if 1
qApp->setStyle(QStyleFactory::create("fusion"));
QPalette palette;
palette.setColor(QPalette::Window, QColor(53,53,53));
palette.setColor(QPalette::WindowText, Qt::white);
palette.setColor(QPalette::Base, QColor(15,15,15));
palette.setColor(QPalette::Base, QColor(25,25,25));
palette.setColor(QPalette::AlternateBase, QColor(53,53,53));
palette.setColor(QPalette::ToolTipBase, Qt::white);
palette.setColor(QPalette::ToolTipText, Qt::white);
palette.setColor(QPalette::ToolTipText, Qt::black);
palette.setColor(QPalette::Text, Qt::white);
palette.setColor(QPalette::Button, QColor(53,53,53));
palette.setColor(QPalette::Button, QColor(0x40, 0x40, 0x40));
palette.setColor(QPalette::ButtonText, Qt::white);
palette.setColor(QPalette::BrightText, Qt::red);
palette.setColor(QPalette::Highlight, QColor(142,45,197).lighter());
palette.setColor(QPalette::Light, QColor(53,53,53).lighter(125).lighter());
palette.setColor(QPalette::Mid, QColor(53,53,53).lighter(125));
palette.setColor(QPalette::Dark, QColor(53,53,53).lighter(125).darker());
palette.setColor(QPalette::Link, QColor(0,0xa0,0xa0));
palette.setColor(QPalette::LinkVisited, QColor(0,0xa0,0xa0).lighter());
palette.setColor(QPalette::Highlight, QColor(0xff, 0x8c, 0x00));
palette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(palette);
#if 0
if(QFontDatabase::addApplicationFont("/tmp/Cuprum.otf") >= 0) {
QFont font("CuprumFFU");
font.setPointSize(10);
qApp->setFont(font);
}
#endif
#if 0
if(QFontDatabase::addApplicationFont("/tmp/PTN57F.ttf") >= 0) {
QFont font("PT Sans Narrow");
font.setPointSize(10);
qApp->setFont(font);
}
#endif
#if 0
if(QFontDatabase::addApplicationFont("/tmp/PTS55F.ttf") >= 0) {
QFont font("PT Sans");
font.setPointSize(10);
qApp->setFont(font);
}
#endif
#if 0
{
QFont font("Ubuntu Condensed");
font.setPointSize(10);
qApp->setFont(font);
}
#endif
#endif
MainWindow w;
w.show();
@ -59,5 +95,7 @@ static int runQtApplication(int argc, char* argv[])
int main(int argc, char* argv[])
{
return runQtApplication(argc, argv);
int res = runQtApplication(argc, argv);
qDebug("regular program exit");
return res;
}

View File

@ -1,4 +1,5 @@
project(demod)
add_subdirectory(nfm)
add_subdirectory(tetra)
#add_subdirectory(nfm)
add_subdirectory(tcpsrc)
#add_subdirectory(tetra)

View File

@ -58,8 +58,6 @@ void NFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBa
void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
{
size_t count = end - begin;
Complex ci;
bool consumed;
@ -74,7 +72,7 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_movingAverage.feed(ci.real() * ci.real() + ci.imag() * ci.imag());
if(m_movingAverage.average() >= m_squelchLevel)
m_squelchState = m_sampleRate / 100;
m_squelchState = m_sampleRate / 50;
if(m_squelchState > 0) {
m_squelchState--;
@ -89,8 +87,11 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if(m_audioBufferFill >= m_audioBuffer.size()) {
if(m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill)
;//qDebug("lost samples");
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
/*
if(res != m_audioBufferFill)
qDebug("lost %u samples", m_audioBufferFill - res);
*/
m_audioBufferFill = 0;
}
}

View File

@ -139,7 +139,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QDockWidget* dockWidget, QWidget*
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(44100);
ui->glSpectrum->setDisplayWaterfall(true);
ui->glSpectrum->setDisplayLiveSpectrum(true);
ui->glSpectrum->setDisplayMaxHold(true);
m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
m_channelMarker = new ChannelMarker(this);

View File

@ -0,0 +1,47 @@
project(tcpsrc)
set(tcpsrc_SOURCES
tcpsrc.cpp
tcpsrcgui.cpp
tcpsrcplugin.cpp
)
set(tcpsrc_HEADERS
tcpsrc.h
tcpsrcgui.h
tcpsrcplugin.h
)
set(tcpsrc_FORMS
tcpsrcgui.ui
)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/include-gpl
${OPENGL_INCLUDE_DIR}
)
#include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
#qt5_wrap_cpp(tcpsrc_HEADERS_MOC ${tcpsrc_HEADERS})
qt5_wrap_ui(tcpsrc_FORMS_HEADERS ${tcpsrc_FORMS})
add_library(demodtcpsrc SHARED
${tcpsrc_SOURCES}
${tcpsrc_HEADERS_MOC}
${tcpsrc_FORMS_HEADERS}
)
target_link_libraries(demodtcpsrc
${QT_LIBRARIES}
${OPENGL_LIBRARIES}
sdrbase
)
qt5_use_modules(demodtcpsrc Core Widgets OpenGL Network)

View File

@ -0,0 +1,82 @@
#include "tcpsrc.h"
#include "dsp/dspcommands.h"
MessageRegistrator TCPSrc::MsgConfigureTCPSrc::ID("MsgConfigureTCPSrc");
TCPSrc::TCPSrc(SampleSink* spectrum)
{
m_inputSampleRate = 100000;
m_sampleFormat = 0;
m_outputSampleRate = 50000;
m_rfBandwidth = 50000;
m_tcpPort = 9999;
m_nco.setFreq(0, m_inputSampleRate);
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.1);
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
m_spectrum = spectrum;
}
TCPSrc::~TCPSrc()
{
}
void TCPSrc::configure(MessageQueue* messageQueue, int sampleFormat, Real outputSampleRate, Real rfBandwidth, int tcpPort)
{
Message* cmd = MsgConfigureTCPSrc::create(sampleFormat, outputSampleRate, rfBandwidth, tcpPort);
cmd->submit(messageQueue, this);
}
void TCPSrc::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
{
Complex ci;
bool consumed;
for(SampleVector::const_iterator it = begin; it < end; ++it) {
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ();
consumed = false;
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &consumed, &ci)) {
m_sampleBuffer.push_back(Sample(ci.real() * 32768.0, ci.imag() * 32768.0));
m_sampleDistanceRemain += m_inputSampleRate / m_outputSampleRate;
}
}
if(m_spectrum != NULL)
m_spectrum->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), firstOfBurst);
m_sampleBuffer.clear();
}
void TCPSrc::start()
{
}
void TCPSrc::stop()
{
}
bool TCPSrc::handleMessage(Message* cmd)
{
if(cmd->id() == DSPSignalNotification::ID()) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
qDebug("%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset());
m_inputSampleRate = signal->getSampleRate();
m_nco.setFreq(-signal->getFrequencyOffset(), m_inputSampleRate);
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.1);
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
cmd->completed();
return true;
} else if(cmd->id() == MsgConfigureTCPSrc::ID()) {
MsgConfigureTCPSrc* cfg = (MsgConfigureTCPSrc*)cmd;
m_sampleFormat = cfg->getSampleFormat();
m_outputSampleRate = cfg->getOutputSampleRate();
m_rfBandwidth = cfg->getRFBandwidth();
m_tcpPort = cfg->getTCPPort();
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.1);
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
cmd->completed();
return true;
} else {
return false;
}
}

View File

@ -0,0 +1,66 @@
#ifndef INCLUDE_TCPSRC_H
#define INCLUDE_TCPSRC_H
#include "dsp/samplesink.h"
#include "dsp/nco.h"
#include "dsp/interpolator.h"
#include "util/message.h"
class TCPSrc : public SampleSink {
public:
TCPSrc(SampleSink* spectrum);
~TCPSrc();
void configure(MessageQueue* messageQueue, int sampleFormat, Real outputSampleRate, Real rfBandwidth, int tcpPort);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst);
void start();
void stop();
bool handleMessage(Message* cmd);
protected:
class MsgConfigureTCPSrc : public Message {
public:
static MessageRegistrator ID;
int getSampleFormat() const { return m_sampleFormat; }
Real getOutputSampleRate() const { return m_outputSampleRate; }
Real getRFBandwidth() const { return m_rfBandwidth; }
int getTCPPort() const { return m_tcpPort; }
static MsgConfigureTCPSrc* create(int sampleFormat, Real sampleRate, Real rfBandwidth, int tcpPort)
{
return new MsgConfigureTCPSrc(sampleFormat, sampleRate, rfBandwidth, tcpPort);
}
private:
int m_sampleFormat;
Real m_outputSampleRate;
Real m_rfBandwidth;
int m_tcpPort;
MsgConfigureTCPSrc(int sampleFormat, Real outputSampleRate, Real rfBandwidth, int tcpPort) :
Message(ID()),
m_sampleFormat(sampleFormat),
m_outputSampleRate(outputSampleRate),
m_rfBandwidth(rfBandwidth),
m_tcpPort(tcpPort)
{ }
};
int m_inputSampleRate;
int m_sampleFormat;
Real m_outputSampleRate;
Real m_rfBandwidth;
int m_tcpPort;
NCO m_nco;
Interpolator m_interpolator;
Real m_sampleDistanceRemain;
SampleVector m_sampleBuffer;
SampleSink* m_spectrum;
};
#endif // INCLUDE_TCPSRC_H

View File

@ -0,0 +1,147 @@
#include "tcpsrcgui.h"
#include "plugin/pluginapi.h"
#include "tcpsrc.h"
#include "dsp/channelizer.h"
#include "dsp/spectrumvis.h"
#include "dsp/threadedsamplesink.h"
#include "ui_tcpsrcgui.h"
TCPSrcGUI* TCPSrcGUI::create(PluginAPI* pluginAPI)
{
TCPSrcGUI* gui = new TCPSrcGUI(pluginAPI);
return gui;
}
void TCPSrcGUI::destroy()
{
delete this;
}
void TCPSrcGUI::setName(const QString& name)
{
setObjectName(name);
}
void TCPSrcGUI::resetToDefaults()
{
ui->sampleFormat->setCurrentIndex(0);
ui->sampleRate->setText("25000");
ui->rfBandwidth->setText("20000");
ui->tcpPort->setText("9999");
applySettings();
}
QByteArray TCPSrcGUI::serialize() const
{
return QByteArray();
}
bool TCPSrcGUI::deserialize(const QByteArray& data)
{
return false;
}
bool TCPSrcGUI::handleMessage(Message* message)
{
return false;
}
void TCPSrcGUI::channelMarkerChanged()
{
applySettings();
}
TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, QWidget* parent) :
RollupWidget(parent),
ui(new Ui::TCPSrcGUI),
m_pluginAPI(pluginAPI)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_tcpSrc = new TCPSrc(m_spectrumVis);
m_channelizer = new Channelizer(m_tcpSrc);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(ui->sampleRate->text().toInt());
ui->glSpectrum->setDisplayWaterfall(true);
ui->glSpectrum->setDisplayMaxHold(true);
m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
m_channelMarker = new ChannelMarker(this);
m_channelMarker->setColor(Qt::red);
m_channelMarker->setBandwidth(25000);
m_channelMarker->setCenterFrequency(0);
m_channelMarker->setVisible(true);
connect(m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_pluginAPI->addChannelMarker(m_channelMarker);
applySettings();
}
TCPSrcGUI::~TCPSrcGUI()
{
m_pluginAPI->removeChannelInstance(this);
delete ui;
}
void TCPSrcGUI::applySettings()
{
bool ok;
Real outputSampleRate = ui->sampleRate->text().toDouble(&ok);
if((!ok) || (outputSampleRate < 100))
outputSampleRate = 25000;
Real rfBandwidth = ui->rfBandwidth->text().toDouble(&ok);
if((!ok) || (rfBandwidth > outputSampleRate))
rfBandwidth = outputSampleRate / 1.05;
int tcpPort = ui->tcpPort->text().toInt(&ok);
if((!ok) || (tcpPort < 1) || (tcpPort > 65535))
tcpPort = 9999;
ui->sampleRate->setText(QString("%1").arg(outputSampleRate, 0));
ui->rfBandwidth->setText(QString("%1").arg(rfBandwidth, 0));
ui->tcpPort->setText(QString("%1").arg(tcpPort));
m_channelMarker->setBandwidth(rfBandwidth);
ui->glSpectrum->setSampleRate(outputSampleRate);
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
outputSampleRate,
m_channelMarker->getCenterFrequency());
m_tcpSrc->configure(m_threadedSampleSink->getMessageQueue(),
ui->sampleFormat->currentIndex(),
outputSampleRate,
rfBandwidth,
tcpPort);
ui->applyBtn->setEnabled(false);
}
void TCPSrcGUI::on_sampleFormat_currentIndexChanged(int index)
{
ui->applyBtn->setEnabled(true);
}
void TCPSrcGUI::on_sampleRate_textEdited(const QString& arg1)
{
ui->applyBtn->setEnabled(true);
}
void TCPSrcGUI::on_rfBandwidth_textEdited(const QString& arg1)
{
ui->applyBtn->setEnabled(true);
}
void TCPSrcGUI::on_tcpPort_textEdited(const QString& arg1)
{
ui->applyBtn->setEnabled(true);
}
void TCPSrcGUI::on_applyBtn_clicked()
{
applySettings();
}

View File

@ -0,0 +1,59 @@
#ifndef INCLUDE_TCPSRCGUI_H
#define INCLUDE_TCPSRCGUI_H
#include "gui/rollupwidget.h"
#include "plugin/plugingui.h"
class PluginAPI;
class ChannelMarker;
class ThreadedSampleSink;
class Channelizer;
class TCPSrc;
class SpectrumVis;
namespace Ui {
class TCPSrcGUI;
}
class TCPSrcGUI : public RollupWidget, public PluginGUI {
Q_OBJECT
public:
static TCPSrcGUI* create(PluginAPI* pluginAPI);
void destroy();
void setName(const QString& name);
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
private slots:
void channelMarkerChanged();
void on_sampleFormat_currentIndexChanged(int index);
void on_sampleRate_textEdited(const QString& arg1);
void on_rfBandwidth_textEdited(const QString& arg1);
void on_tcpPort_textEdited(const QString& arg1);
void on_applyBtn_clicked();
private:
Ui::TCPSrcGUI* ui;
PluginAPI* m_pluginAPI;
ChannelMarker* m_channelMarker;
// RF path
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
TCPSrc* m_tcpSrc;
SpectrumVis* m_spectrumVis;
explicit TCPSrcGUI(PluginAPI* pluginAPI, QWidget* parent = NULL);
~TCPSrcGUI();
void applySettings();
};
#endif // INCLUDE_TCPSRCGUI_H

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TCPSrcGUI</class>
<widget class="RollupWidget" name="TCPSrcGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>443</height>
</rect>
</property>
<property name="windowTitle">
<string>TCP Sample Source</string>
</property>
<widget class="QWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>10</x>
<y>5</y>
<width>201</width>
<height>142</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>2</number>
</property>
<property name="spacing">
<number>3</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Sample Format</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="tcpPort">
<property name="text">
<string>9999</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>RF Bandwidth</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="sampleRate">
<property name="text">
<string>25000</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="rfBandwidth">
<property name="text">
<string>20000</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Samplerate</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>TCP Port</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="sampleFormat">
<item>
<property name="text">
<string>S8 I/Q</string>
</property>
</item>
<item>
<property name="text">
<string>S16LE I/Q</string>
</property>
</item>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="applyBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="widget_3" native="true">
<property name="geometry">
<rect>
<x>15</x>
<y>160</y>
<width>231</width>
<height>156</height>
</rect>
</property>
<property name="windowTitle">
<string>Channel Spectrum</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>3</number>
</property>
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="GLSpectrum" name="glSpectrum" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="widget_2" native="true">
<property name="geometry">
<rect>
<x>15</x>
<y>330</y>
<width>274</width>
<height>101</height>
</rect>
</property>
<property name="windowTitle">
<string>Connected Clients</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>IP:Port</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrum</class>
<extends>QWidget</extends>
<header>gui/glspectrum.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>sampleFormat</tabstop>
<tabstop>sampleRate</tabstop>
<tabstop>rfBandwidth</tabstop>
<tabstop>tcpPort</tabstop>
<tabstop>applyBtn</tabstop>
<tabstop>treeWidget</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,55 @@
#include <QtPlugin>
#include <QAction>
#include "plugin/pluginapi.h"
#include "tcpsrcplugin.h"
#include "tcpsrcgui.h"
const PluginDescriptor TCPSrcPlugin::m_pluginDescriptor = {
QString("TCP Channel Source"),
QString("---"),
QString("(c) maintech GmbH (written by Christian Daniel)"),
QString("http://www.maintech.de"),
true,
QString("http://www.maintech.de")
};
TCPSrcPlugin::TCPSrcPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& TCPSrcPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void TCPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
// register TCP Channel Source
QAction* action = new QAction(tr("&TCP Source"), this);
connect(action, SIGNAL(triggered()), this, SLOT(createInstanceTCPSrc()));
m_pluginAPI->registerChannel("de.maintech.sdrangelove.channel.tcpsrc", this, action);
}
PluginGUI* TCPSrcPlugin::createChannel(const QString& channelName)
{
if(channelName == "de.maintech.sdrangelove.channel.tcpsrc") {
TCPSrcGUI* gui = TCPSrcGUI::create(m_pluginAPI);
m_pluginAPI->registerChannelInstance("de.maintech.sdrangelove.channel.tcpsrc", gui);
m_pluginAPI->addChannelRollup(gui);
return gui;
} else {
return NULL;
}
}
void TCPSrcPlugin::createInstanceTCPSrc()
{
TCPSrcGUI* gui = TCPSrcGUI::create(m_pluginAPI);
m_pluginAPI->registerChannelInstance("de.maintech.sdrangelove.channel.tcpsrc", gui);
m_pluginAPI->addChannelRollup(gui);
//m_pluginAPI->registerChannelInstance("de.maintech.sdrangelove.channel.tcpsrc", TCPSrcGUI::create(m_pluginAPI));
}

View File

@ -0,0 +1,29 @@
#ifndef INCLUDE_TCPSRCPLUGIN_H
#define INCLUDE_TCPSRCPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class TCPSrcPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "de.maintech.sdrangelove.demod.tcpsrc")
public:
explicit TCPSrcPlugin(QObject* parent = NULL);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
PluginGUI* createChannel(const QString& channelName);
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
private slots:
void createInstanceTCPSrc();
};
#endif // INCLUDE_TCPSRCPLUGIN_H

View File

@ -79,7 +79,7 @@ TetraDemodGUI::TetraDemodGUI(PluginAPI* pluginAPI, QDockWidget* dockWidget, QWid
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(36000);
ui->glSpectrum->setDisplayWaterfall(true);
ui->glSpectrum->setDisplayLiveSpectrum(true);
ui->glSpectrum->setDisplayMaxHold(true);
m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
m_channelMarker = new ChannelMarker(this);

View File

@ -3,7 +3,7 @@
#include "plugin/pluginapi.h"
OsmoSDRGui::OsmoSDRGui(PluginAPI* pluginAPI, QWidget* parent) :
PluginGUI(parent),
QWidget(parent),
ui(new Ui::OsmoSDRGui),
m_pluginAPI(pluginAPI),
m_settings(),
@ -28,6 +28,11 @@ void OsmoSDRGui::destroy()
delete this;
}
void OsmoSDRGui::setName(const QString& name)
{
setObjectName(name);
}
void OsmoSDRGui::resetToDefaults()
{
m_generalSettings.resetToDefaults();

View File

@ -11,7 +11,7 @@ namespace Ui {
class OsmoSDRGui;
}
class OsmoSDRGui : public PluginGUI {
class OsmoSDRGui : public QWidget, public PluginGUI {
Q_OBJECT
public:
@ -19,6 +19,8 @@ public:
~OsmoSDRGui();
void destroy();
void setName(const QString& name);
void resetToDefaults();
QByteArray serializeGeneral() const;
bool deserializeGeneral(const QByteArray&data);
@ -28,14 +30,6 @@ public:
bool handleMessage(Message* message);
private:
/*
Ui::OsmoSDRGui* ui;
MessageQueue* m_msgQueue;
OsmoSDRInput::Settings m_settings;
QTimer m_updateTimer;
*/
Ui::OsmoSDRGui* ui;
PluginAPI* m_pluginAPI;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>253</width>
<height>224</height>
<height>229</height>
</rect>
</property>
<property name="sizePolicy">
@ -118,10 +118,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
<property name="tickInterval">
<number>1</number>
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>

View File

@ -48,17 +48,21 @@ PluginInterface::SampleSourceDevices OsmoSDRPlugin::enumSampleSources()
if(osmosdr_get_device_usb_strings(i, vendor, product, serial) != 0)
continue;
QString displayedName(QString("OsmoSDR #%1 (#%2)").arg(i + 1).arg(serial));
qDebug("found %s", qPrintable(displayedName));
SimpleSerializer s(1);
s.writeS32(1, i);
result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.osmo-sdr", s.final()));
}
return result;
}
PluginGUI* OsmoSDRPlugin::createSampleSource(const QString& sourceName, const QByteArray& address)
{
if(sourceName == "org.osmocom.sdr.samplesource.osmo-sdr") {
return new OsmoSDRGui(m_pluginAPI);
OsmoSDRGui* gui = new OsmoSDRGui(m_pluginAPI);
m_pluginAPI->setInputGUI(gui);
return gui;
} else {
return NULL;
}

View File

@ -3,7 +3,7 @@
#include "plugin/pluginapi.h"
RTLSDRGui::RTLSDRGui(PluginAPI* pluginAPI, QWidget* parent) :
PluginGUI(parent),
QWidget(parent),
ui(new Ui::RTLSDRGui),
m_pluginAPI(pluginAPI),
m_settings(),
@ -28,6 +28,11 @@ void RTLSDRGui::destroy()
delete this;
}
void RTLSDRGui::setName(const QString& name)
{
setObjectName(name);
}
void RTLSDRGui::resetToDefaults()
{
m_generalSettings.resetToDefaults();

View File

@ -11,7 +11,7 @@ namespace Ui {
class RTLSDRGui;
}
class RTLSDRGui : public PluginGUI {
class RTLSDRGui : public QWidget, public PluginGUI {
Q_OBJECT
public:
@ -19,6 +19,8 @@ public:
~RTLSDRGui();
void destroy();
void setName(const QString& name);
void resetToDefaults();
QByteArray serializeGeneral() const;
bool deserializeGeneral(const QByteArray&data);

View File

@ -58,7 +58,9 @@ PluginInterface::SampleSourceDevices RTLSDRPlugin::enumSampleSources()
PluginGUI* RTLSDRPlugin::createSampleSource(const QString& sourceName, const QByteArray& address)
{
if(sourceName == "org.osmocom.sdr.samplesource.rtl-sdr") {
return new RTLSDRGui(m_pluginAPI);
RTLSDRGui* gui = new RTLSDRGui(m_pluginAPI);
m_pluginAPI->setInputGUI(gui);
return gui;
} else {
return NULL;
}

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>476</width>
<height>499</height>
<width>484</width>
<height>503</height>
</rect>
</property>
<property name="windowTitle">
@ -78,19 +78,15 @@
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:8pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Höchberg, Germany&lt;br /&gt;Written by Christian Daniel.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Many thanks to the osmocom developer team - especially horizon, Hoernchen &amp;amp; tnt.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;SDRangelove itself is licensed as &amp;quot;GPL2+&amp;quot; with the added exception, that plugins using only header files from the &amp;quot;include&amp;quot;-subdirectory and not from the &amp;quot;include-gpl&amp;quot;-subdirectory do not count as derived works.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The following rules apply to the SDRangelove main application and libsdrbase:&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;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; either version 2 of the License, or (at your option) any later version.&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;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.&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;You should have received a copy of the GNU General Public License along with this program. If not, see &lt;a href=&quot;http://www.gnu.org/licenses/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#502878;&quot;&gt;http://www.gnu.org/licenses/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#502878;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;For the license of installed plugins, look into the plugin list.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;p&gt;Copyright (C) 2013 maintech GmbH, Otto-Hahn-Str. 15, 97204 Höchberg, Germany&lt;br&gt;
Written by Christian Daniel.&lt;/p&gt;
&lt;p&gt;Many thanks to the osmocom developer team - especially horizon, Hoernchen &amp;amp; tnt.&lt;/p&gt;
&lt;p&gt;SDRangelove itself is licensed as &quot;GPL2+&quot; with the added exception, that plugins using only header files from the &quot;include&quot;-subdirectory and not from the &quot;include-gpl&quot;-subdirectory do not count as derived works.&lt;/p&gt;
&lt;p&gt;The following rules apply to the SDRangelove main application and libsdrbase:&lt;br&gt;
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; either version 2 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.
You should have received a copy of the GNU General Public License along with this program. If not, see &lt;a href=&quot;http://www.gnu.org/licenses/&quot;&gt;http://www.gnu.org/licenses/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the license of installed plugins, look into the plugin list.&lt;/p&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>

View File

@ -0,0 +1,21 @@
#include <QPainter>
#include "gui/buttonswitch.h"
ButtonSwitch::ButtonSwitch(QWidget* parent) :
QToolButton(parent)
{
setCheckable(true);
m_originalPalette = palette();
connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));
}
void ButtonSwitch::onToggled(bool checked)
{
if(checked) {
QPalette p = m_originalPalette;
p.setColor(QPalette::Button, QColor(0x80, 0x46, 0x00));
setPalette(p);
} else {
setPalette(m_originalPalette);
}
}

View File

@ -0,0 +1,36 @@
#include <QBoxLayout>
#include <QSpacerItem>
#include <QPainter>
#include <QResizeEvent>
#include "gui/channelwindow.h"
#include "gui/rollupwidget.h"
ChannelWindow::ChannelWindow(QWidget* parent) :
QScrollArea(parent)
{
m_container = new QWidget(this);
m_layout = new QBoxLayout(QBoxLayout::TopToBottom, m_container);
setWidget(m_container);
setWidgetResizable(true);
setBackgroundRole(QPalette::Base);
m_layout->setMargin(3);
m_layout->setSpacing(3);
}
void ChannelWindow::addRollupWidget(QWidget* rollupWidget)
{
rollupWidget->setParent(m_container);
m_container->layout()->addWidget(rollupWidget);
}
void ChannelWindow::resizeEvent(QResizeEvent* event)
{
if(event->size().height() > event->size().width()) {
m_layout->setDirection(QBoxLayout::TopToBottom);
m_layout->setAlignment(Qt::AlignTop);
} else {
m_layout->setDirection(QBoxLayout::LeftToRight);
m_layout->setAlignment(Qt::AlignLeft);
}
QScrollArea::resizeEvent(event);
}

View File

@ -419,6 +419,22 @@ void GLScope::handleMode()
}
break;
}
case ModeCyclostationary: {
if(m_rawTrace.size() > 2) {
m_mathTrace.resize(m_rawTrace.size() - 2);
std::vector<Complex>::iterator dst = m_mathTrace.begin();
for(uint i = 2; i < m_rawTrace.size() ; i++)
*dst++ = Complex(abs(m_rawTrace[i] - conj(m_rawTrace[i - 1])), 0);
m_displayTrace = &m_mathTrace;
m_amp1 = m_amp;
m_amp2 = m_amp;
m_ofs1 = -1.0 / m_amp1;
m_ofs2 = 0.0;
}
break;
}
}
}

View File

@ -29,8 +29,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) :
m_sampleRate(500000),
m_fftSize(512),
m_invertedWaterfall(false),
m_displayLiveSpectrum(false),
m_liveSpectrumChanged(false),
m_displayMaxHold(false),
m_leftMarginTextureAllocated(false),
m_frequencyTextureAllocated(false),
m_waterfallBuffer(NULL),
@ -51,7 +50,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) :
setMinimumSize(200, 200);
m_waterfallShare = 0.5;
m_waterfallShare = 0.66;
for(int i = 0; i <= 239; i++) {
QColor c;
@ -182,9 +181,9 @@ void GLSpectrum::setInvertedWaterfall(bool inv)
update();
}
void GLSpectrum::setDisplayLiveSpectrum(bool display)
void GLSpectrum::setDisplayMaxHold(bool display)
{
m_displayLiveSpectrum = display;
m_displayMaxHold = display;
m_changesPending = true;
stopDrag();
update();
@ -245,11 +244,6 @@ void GLSpectrum::newSpectrum(const std::vector<Real>& spectrum, int fftSize)
updateWaterfall(spectrum);
updateHistogram(spectrum);
if(!m_liveSpectrumChanged) {
std::copy(spectrum.begin(), spectrum.begin() + m_fftSize, m_liveSpectrum.begin());
m_liveSpectrumChanged = true;
}
}
void GLSpectrum::updateWaterfall(const std::vector<Real>& spectrum)
@ -440,7 +434,7 @@ void GLSpectrum::paintGL()
}
// paint histogram
if(m_displayHistogram || m_displayLiveSpectrum) {
if(m_displayHistogram || m_displayMaxHold) {
glPushMatrix();
glTranslatef(m_glHistogramRect.x(), m_glHistogramRect.y(), 0);
glScalef(m_glHistogramRect.width(), m_glHistogramRect.height(), 1);
@ -522,7 +516,7 @@ void GLSpectrum::paintGL()
}
// paint left scales (time and power)
if(m_displayWaterfall || m_displayLiveSpectrum || m_displayHistogram ) {
if(m_displayWaterfall || m_displayMaxHold || m_displayHistogram ) {
glBindTexture(GL_TEXTURE_2D, m_leftMarginTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -549,7 +543,7 @@ void GLSpectrum::paintGL()
}
// paint frequency scale
if(m_displayWaterfall || m_displayLiveSpectrum || m_displayHistogram ) {
if(m_displayWaterfall || m_displayMaxHold || m_displayHistogram ) {
glBindTexture(GL_TEXTURE_2D, m_frequencyTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -575,10 +569,48 @@ void GLSpectrum::paintGL()
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
// paint channels
glPushMatrix();
glTranslatef(m_glWaterfallRect.x(), m_glFrequencyScaleRect.y(), 0);
glScalef(m_glWaterfallRect.width(), m_glFrequencyScaleRect.height(), 1);
for(int i = 0; i < m_channelMarkerStates.size(); ++i) {
ChannelMarkerState* dv = m_channelMarkerStates[i];
if(dv->m_channelMarker->getVisible()) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(dv->m_channelMarker->getColor().redF(), dv->m_channelMarker->getColor().greenF(), dv->m_channelMarker->getColor().blueF(), 0.3f);
glPushMatrix();
glTranslatef(dv->m_glRect.x(), dv->m_glRect.y(), 0);
glScalef(dv->m_glRect.width(), dv->m_glRect.height(), 1);
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(1, 0);
glVertex2f(1, 1);
glVertex2f(0, 1);
glEnd();
glDisable(GL_BLEND);
glPopMatrix();
}
}
glPopMatrix();
}
// paint live spectrum lines on top of histogram
if(m_displayLiveSpectrum) {
// paint max hold lines on top of histogram
if(m_displayMaxHold) {
if(m_maxHold.size() < m_fftSize)
m_maxHold.resize(m_fftSize);
for(int i = 0; i < m_fftSize; i++) {
int j;
quint8* bs = m_histogram + i * 100;
for(j = 99; j > 0; j--) {
if(bs[j] > 0)
break;
}
j = j - 99;
m_maxHold[i] = (j * m_powerRange) / 99.0 + m_referenceLevel;
}
glPushMatrix();
glTranslatef(m_glHistogramRect.x(), m_glHistogramRect.y(), 0);
glScalef(m_glHistogramRect.width() / (float)(m_fftSize - 1), -m_glHistogramRect.height() / m_powerRange, 1);
@ -586,11 +618,11 @@ void GLSpectrum::paintGL()
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
glColor4f(1, 1, 1, 0.75f);
glColor3f(1, 0, 0);
Real bottom = -m_powerRange;
glBegin(GL_LINE_STRIP);
for(int i = 0; i < m_fftSize; i++) {
Real v = m_liveSpectrum[i] - m_referenceLevel;
Real v = m_maxHold[i] - m_referenceLevel;
if(v > 0)
v = 0;
else if(v < bottom)
@ -601,7 +633,6 @@ void GLSpectrum::paintGL()
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
}
m_liveSpectrumChanged = false;
// paint waterfall grid
if(m_displayWaterfall) {
@ -649,7 +680,7 @@ void GLSpectrum::paintGL()
}
// paint histogram grid
if(m_displayHistogram || m_displayLiveSpectrum) {
if(m_displayHistogram || m_displayMaxHold) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.0f);
@ -718,8 +749,6 @@ void GLSpectrum::applyChanges()
QFontMetrics fm(font());
int M = fm.width("-");
m_liveSpectrum.resize(m_fftSize);
int topMargin = fm.ascent() * 1.5;
int bottomMargin = fm.ascent() * 1.5;
@ -732,7 +761,7 @@ void GLSpectrum::applyChanges()
int leftMargin;
int rightMargin = fm.width("000");
if(m_displayWaterfall && (m_displayHistogram | m_displayLiveSpectrum)) {
if(m_displayWaterfall && (m_displayHistogram | m_displayMaxHold)) {
waterfallHeight = height() * m_waterfallShare - 1;
if(waterfallHeight < 0)
waterfallHeight = 0;
@ -848,7 +877,7 @@ void GLSpectrum::applyChanges()
(float)(leftMargin - 1) / (float)width(),
(float)1
);
} else if(m_displayHistogram || m_displayLiveSpectrum) {
} else if(m_displayHistogram || m_displayMaxHold) {
bottomMargin = frequencyScaleHeight;
frequencyScaleTop = height() - bottomMargin;
histogramTop = topMargin - 1;
@ -902,7 +931,7 @@ void GLSpectrum::applyChanges()
0,
(dv->m_channelMarker->getBandwidth() / (float)m_sampleRate),
1);
if(m_displayHistogram || m_displayLiveSpectrum || m_displayWaterfall) {
if(m_displayHistogram || m_displayMaxHold || m_displayWaterfall) {
dv->m_rect.setRect(m_frequencyScale.getPosFromValue(m_centerFrequency + dv->m_channelMarker->getCenterFrequency()) + leftMargin - 1,
topMargin,
5,
@ -929,7 +958,7 @@ void GLSpectrum::applyChanges()
}
}
}
if(m_displayHistogram || m_displayLiveSpectrum) {
if(m_displayHistogram || m_displayMaxHold) {
tickList = &m_powerScale.getTickList();
for(int i = 0; i < tickList->count(); i++) {
tick = &(*tickList)[i];
@ -950,13 +979,14 @@ void GLSpectrum::applyChanges()
m_leftMarginTextureAllocated = true;
}
// prepare frequency scale
if(m_displayWaterfall || m_displayHistogram || m_displayLiveSpectrum){
if(m_displayWaterfall || m_displayHistogram || m_displayMaxHold){
m_frequencyPixmap = QPixmap(width(), frequencyScaleHeight);
m_frequencyPixmap.fill(Qt::transparent);
{
QPainter painter(&m_frequencyPixmap);
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::black);
painter.setBrush(Qt::transparent);
painter.drawRect(leftMargin, 0, width() - leftMargin, frequencyScaleHeight);
painter.setPen(QColor(0xf0, 0xf0, 0xff));
const ScaleEngine::TickList* tickList = &m_frequencyScale.getTickList();
@ -1056,7 +1086,7 @@ void GLSpectrum::applyChanges()
void GLSpectrum::mouseMoveEvent(QMouseEvent* event)
{
if(m_displayWaterfall && (m_displayWaterfall || m_displayHistogram || m_displayLiveSpectrum)) {
if(m_displayWaterfall && (m_displayWaterfall || m_displayHistogram || m_displayMaxHold)) {
if(m_frequencyScaleRect.contains(event->pos())) {
if(m_cursorState == CSNormal) {
setCursor(Qt::SizeVerCursor);
@ -1090,7 +1120,7 @@ void GLSpectrum::mouseMoveEvent(QMouseEvent* event)
m_channelMarkerStates[m_cursorChannel]->m_channelMarker->setCenterFrequency(freq);
}
if(m_displayWaterfall || m_displayHistogram || m_displayLiveSpectrum) {
if(m_displayWaterfall || m_displayHistogram || m_displayMaxHold) {
for(int i = 0; i < m_channelMarkerStates.size(); ++i) {
if(m_channelMarkerStates[i]->m_rect.contains(event->pos())) {
if(m_cursorState == CSNormal) {

View File

@ -2,8 +2,8 @@
#include "dsp/fftwindow.h"
#include "dsp/spectrumvis.h"
#include "gui/glspectrum.h"
#include "ui_glspectrumgui.h"
#include "util/simpleserializer.h"
#include "ui_glspectrumgui.h"
GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
QWidget(parent),
@ -18,7 +18,7 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
m_powerRange(100),
m_displayWaterfall(true),
m_invertedWaterfall(false),
m_displayLiveSpectrum(false),
m_displayMaxHold(false),
m_displayHistogram(true)
{
ui->setupUi(this);
@ -46,7 +46,7 @@ void GLSpectrumGUI::resetToDefaults()
m_powerRange = 100;
m_displayWaterfall = true;
m_invertedWaterfall = false;
m_displayLiveSpectrum = false;
m_displayMaxHold = false;
m_displayHistogram = true;
applySettings();
}
@ -61,7 +61,7 @@ QByteArray GLSpectrumGUI::serialize() const
s.writeReal(5, m_powerRange);
s.writeBool(6, m_displayWaterfall);
s.writeBool(7, m_invertedWaterfall);
s.writeBool(8, m_displayLiveSpectrum);
s.writeBool(8, m_displayMaxHold);
s.writeBool(9, m_displayHistogram);
return s.final();
}
@ -83,7 +83,7 @@ bool GLSpectrumGUI::deserialize(const QByteArray& data)
d.readReal(5, &m_powerRange, 100);
d.readBool(6, &m_displayWaterfall, true);
d.readBool(7, &m_invertedWaterfall, false);
d.readBool(8, &m_displayLiveSpectrum, false);
d.readBool(8, &m_displayMaxHold, false);
d.readBool(9, &m_displayHistogram, true);
applySettings();
return true;
@ -105,8 +105,8 @@ void GLSpectrumGUI::applySettings()
ui->waterfall->setChecked(m_displayWaterfall);
m_glSpectrum->setDisplayWaterfall(m_displayWaterfall);
m_glSpectrum->setInvertedWaterfall(m_invertedWaterfall);
ui->liveSpectrum->setChecked(m_displayLiveSpectrum);
m_glSpectrum->setDisplayLiveSpectrum(m_displayLiveSpectrum);
ui->maxHold->setChecked(m_displayMaxHold);
m_glSpectrum->setDisplayMaxHold(m_displayMaxHold);
ui->histogram->setChecked(m_displayHistogram);
m_glSpectrum->setDisplayHistogram(m_displayHistogram);
ui->refLevel->setValue((int)(m_refLevel / 10.0));
@ -158,8 +158,8 @@ void GLSpectrumGUI::on_histogram_toggled(bool checked)
m_glSpectrum->setDisplayHistogram(m_displayHistogram);
}
void GLSpectrumGUI::on_liveSpectrum_toggled(bool checked)
void GLSpectrumGUI::on_maxHold_toggled(bool checked)
{
m_displayLiveSpectrum = checked;
m_glSpectrum->setDisplayLiveSpectrum(m_displayLiveSpectrum);
m_displayMaxHold = checked;
m_glSpectrum->setDisplayMaxHold(m_displayMaxHold);
}

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>203</width>
<height>136</height>
<height>137</height>
</rect>
</property>
<property name="windowTitle">
@ -48,7 +48,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
@ -85,7 +85,7 @@
</widget>
</item>
<item row="1" column="4">
<widget class="QToolButton" name="waterfall">
<widget class="ButtonSwitch" name="waterfall">
<property name="minimumSize">
<size>
<width>24</width>
@ -144,7 +144,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
@ -174,7 +174,7 @@
</widget>
</item>
<item row="2" column="4">
<widget class="QToolButton" name="histogram">
<widget class="ButtonSwitch" name="histogram">
<property name="minimumSize">
<size>
<width>24</width>
@ -233,7 +233,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>10</number>
@ -263,7 +263,7 @@
</widget>
</item>
<item row="3" column="4">
<widget class="QToolButton" name="liveSpectrum">
<widget class="ButtonSwitch" name="maxHold">
<property name="minimumSize">
<size>
<width>24</width>
@ -278,7 +278,7 @@
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/livespectrum.png</normaloff>:/livespectrum.png</iconset>
<normaloff>:/maxhold.png</normaloff>:/maxhold.png</iconset>
</property>
<property name="iconSize">
<size>
@ -390,7 +390,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
@ -401,6 +401,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>fftSize</tabstop>
<tabstop>fftWindow</tabstop>
@ -409,7 +416,7 @@
<tabstop>decay</tabstop>
<tabstop>waterfall</tabstop>
<tabstop>histogram</tabstop>
<tabstop>liveSpectrum</tabstop>
<tabstop>maxHold</tabstop>
</tabstops>
<resources>
<include location="../resources/res.qrc"/>

View File

@ -42,6 +42,7 @@ Indicator::Indicator(const QString& text, QWidget* parent) :
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QFont f = font();
f.setBold(true);
f.setPixelSize(8);
setFont(f);
}

View File

@ -17,7 +17,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">

View File

@ -0,0 +1,231 @@
#include <QEvent>
#include <QPainter>
#include <QMouseEvent>
#include "gui/rollupwidget.h"
#include "ui_glspectrumgui.h"
RollupWidget::RollupWidget(QWidget* parent) :
QWidget(parent)
{
setMinimumSize(250, 150);
setMaximumSize(400, 200);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
setBackgroundRole(QPalette::Window);
setAutoFillBackground(false);
setAttribute(Qt::WA_OpaquePaintEvent, true);
}
void RollupWidget::addRollup(QWidget* rollup)
{
rollup->setParent(this);
installEventFilter(rollup);
arrangeRollups();
repaint();
}
int RollupWidget::arrangeRollups()
{
QFontMetrics fm(font());
int pos = fm.height() + 4;
for(int i = 0; i < children().count(); ++i) {
pos += fm.height() + 2;
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL) {
if(!r->isHidden()) {
r->move(2, pos + 3);
int h = 0;
if(r->hasHeightForWidth())
h = r->heightForWidth(width() - 4);
else h = r->sizeHint().height();
r->resize(width() - 4, h);
pos += r->height() + 5;
}
}
}
setMinimumHeight(pos);
setMaximumHeight(pos);
return pos;
}
void RollupWidget::paintEvent(QPaintEvent*)
{
QPainter p(this);
QColor frame = palette().highlight().color();
// Eigenbau
QFontMetrics fm(font());
p.setRenderHint(QPainter::Antialiasing, true);
// Ecken
p.setPen(Qt::NoPen);
p.setBrush(palette().base());
p.drawRect(0, 0, 5, 5);
p.drawRect(width() - 5, 0, 5, 5);
p.drawRect(0, height() - 5, 5, 5);
p.drawRect(width() - 5, height() - 5, 5, 5);
// Rahmen
p.setPen(frame);
p.setBrush(palette().window());
QRectF r(rect());
r.adjust(0.5, 0.5, -0.5, -0.5);
p.drawRoundedRect(r, 3.0, 3.0, Qt::AbsoluteSize);
// Titel-Hintergrund
p.setPen(Qt::NoPen);
p.setBrush(palette().highlight());
QPainterPath path;
path.moveTo(1.5, fm.height() + 2.5);
path.lineTo(width() - 1.5, fm.height() + 2.5);
path.lineTo(width() - 1.5, 3.5);
path.arcTo(QRectF(width() - 3.5, 0, 2.5, 2.5), 270, -90);
path.lineTo(3.5, 1.5);
path.arcTo(QRectF(1.5, 2.5, 2.5, 2.5), 90, 90);
p.drawPath(path);
// Titel-Abschlusslinie
p.setPen(frame);
p.drawLine(QPointF(0.5, 2 + fm.height() + 1.5), QPointF(width() - 1.5, 2 + fm.height() + 1.5));
// Aktiv-Button links
p.setPen(QPen(palette().windowText().color(), 1.0));
p.setBrush(palette().light());
p.drawRoundedRect(QRectF(3.5, 3.5, fm.ascent(), fm.ascent()), 2.0, 2.0, Qt::AbsoluteSize);
// Schließen-Button rechts
p.setRenderHint(QPainter::Antialiasing, true);
p.setPen(QPen(palette().windowText().color(), 1.0));
p.setBrush(palette().light());
r = QRectF(width() - 3.5 - fm.ascent(), 3.5, fm.ascent(), fm.ascent());
p.drawRoundedRect(r, 2.0, 2.0, Qt::AbsoluteSize);
p.setPen(QPen(palette().windowText().color(), 1.5));
p.drawLine(r.topLeft() + QPointF(1, 1), r.bottomRight() + QPointF(-1, -1));
p.drawLine(r.bottomLeft() + QPointF(1, -1), r.topRight() + QPointF(-1, 1));
// Titel
p.setPen(palette().highlightedText().color());
p.drawText(QRect(2 + fm.height(), 2, width() - 4 - 2 * fm.height(), fm.height()),
fm.elidedText(windowTitle(), Qt::ElideMiddle, width() - 4 - 2 * fm.height(), 0));
// Rollups
int pos = fm.height() + 4;
for(int i = 0; i < children().count(); ++i) {
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL)
pos += paintRollup(r, pos, &p, i == children().count() - 1, frame);
}
}
int RollupWidget::paintRollup(QWidget* rollup, int pos, QPainter* p, bool last, const QColor& frame)
{
QFontMetrics fm(font());
int height = 1;
// Titel-Abschlusslinie
if(!rollup->isHidden()) {
p->setPen(palette().dark().color());
p->drawLine(QPointF(1.5, pos + fm.height() + 1.5), QPointF(width() - 1.5, pos + fm.height() + 1.5));
p->setPen(palette().light().color());
p->drawLine(QPointF(1.5, pos + fm.height() + 2.5), QPointF(width() - 1.5, pos + fm.height() + 2.5));
height += 2;
} else {
if(!last) {
p->setPen(frame);
p->drawLine(QPointF(1.5, pos + fm.height() + 1.5), QPointF(width() - 1.5, pos + fm.height() + 1.5));
height++;
}
}
// Titel
p->setPen(palette().windowText().color());
p->drawText(QRect(2 + fm.height(), pos, width() - 4 - fm.height(), fm.height()),
fm.elidedText(rollup->windowTitle(), Qt::ElideMiddle, width() - 4 - fm.height(), 0));
height += fm.height();
// Ausklapp-Icon
p->setPen(palette().windowText().color());
p->setBrush(palette().windowText());
if(!rollup->isHidden()) {
QPolygonF a;
a.append(QPointF(3.5, pos + 2));
a.append(QPointF(3.5 + fm.ascent(), pos + 2));
a.append(QPointF(3.5 + fm.ascent() / 2.0, pos + fm.height() - 2));
p->drawPolygon(a);
} else {
QPolygonF a;
a.append(QPointF(3.5, pos + 2));
a.append(QPointF(3.5, pos + fm.height() - 2));
a.append(QPointF(3.5 + fm.ascent(), pos + fm.height() / 2));
p->drawPolygon(a);
}
// Inhalt
if(!rollup->isHidden() && (!last)) {
// Rollup-Abschlusslinie
p->setPen(frame);
p->drawLine(QPointF(1.5, pos + fm.height() + rollup->height() + 6.5),
QPointF(width() - 1.5, pos + fm.height() + rollup->height() + 6.5));
height += rollup->height() + 4;
}
return height;
}
void RollupWidget::resizeEvent(QResizeEvent* size)
{
arrangeRollups();
QWidget::resizeEvent(size);
}
void RollupWidget::mousePressEvent(QMouseEvent* event)
{
QFontMetrics fm(font());
// menu box left
if(QRectF(3.5, 3.5, fm.ascent(), fm.ascent()).contains(event->pos())) {
emit customContextMenuRequested(event->pos());
return;
}
// close button right
if(QRectF(width() - 3.5 - fm.ascent(), 3.5, fm.ascent(), fm.ascent()).contains(event->pos())) {
close();
return;
}
// check if we need to change a rollup widget
int pos = fm.height() + 4;
for(int i = 0; i < children().count(); ++i) {
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL) {
if((event->y() >= pos) && (event->y() < (pos + fm.height() + 3))) {
if(r->isHidden())
r->show();
else r->hide();
arrangeRollups();
repaint();
return;
} else {
pos += fm.height() + 2;
if(!r->isHidden())
pos += r->height() + 5;
}
}
}
}
bool RollupWidget::eventFilter(QObject* object, QEvent* event)
{
if((event->type() == QEvent::Show) || (event->type() == QEvent::Hide)) {
if(children().contains(object))
arrangeRollups();
} else if((event->type() == QEvent::ChildAdded) || (event->type() == QEvent::ChildRemoved)) {
if(children().contains(object))
arrangeRollups();
}
return QWidget::eventFilter(object, event);
}

View File

@ -135,6 +135,10 @@ void ScopeWindow::on_displayMode_currentIndexChanged(int index)
case 3: // derived1+derived2
ui->scope->setMode(GLScope::ModeDerived12);
break;
case 4: // clostationary
ui->scope->setMode(GLScope::ModeCyclostationary);
break;
default:
break;
}

View File

@ -82,6 +82,11 @@
<string>Derived 1st + 2nd order</string>
</property>
</item>
<item>
<property name="text">
<string>Cyclostationary</string>
</property>
</item>
</widget>
</item>
<item>

View File

@ -17,7 +17,6 @@
#include <QInputDialog>
#include <QMessageBox>
#include <QDir>
#include <QLabel>
#include "mainwindow.h"
#include "ui_mainwindow.h"
@ -29,6 +28,7 @@
#include "gui/pluginsdialog.h"
#include "gui/preferencesdialog.h"
#include "gui/aboutdialog.h"
#include "gui/rollupwidget.h"
#include "dsp/dspengine.h"
#include "dsp/spectrumvis.h"
#include "dsp/dspcommands.h"
@ -59,20 +59,25 @@ MainWindow::MainWindow(QWidget* parent) :
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
// work around broken Qt dock widget ordering
removeDockWidget(ui->inputDock);
removeDockWidget(ui->processingDock);
removeDockWidget(ui->presetDock);
removeDockWidget(ui->channelDock);
addDockWidget(Qt::LeftDockWidgetArea, ui->inputDock);
addDockWidget(Qt::LeftDockWidgetArea, ui->processingDock);
addDockWidget(Qt::LeftDockWidgetArea, ui->presetDock);
addDockWidget(Qt::RightDockWidgetArea, ui->channelDock);
ui->inputDock->show();
ui->processingDock->show();
ui->presetDock->show();
ui->channelDock->show();
ui->menu_Window->addAction(ui->inputDock->toggleViewAction());
ui->menu_Window->addAction(ui->processingDock->toggleViewAction());
ui->menu_Window->addAction(ui->presetDock->toggleViewAction());
ui->menu_Window->addAction(ui->channelDock->toggleViewAction());
connect(m_messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()), Qt::QueuedConnection);
@ -131,9 +136,14 @@ MainWindow::~MainWindow()
delete ui;
}
void MainWindow::addDemodCreateAction(QAction* action)
void MainWindow::addChannelCreateAction(QAction* action)
{
ui->menu_Demodulation->addAction(action);
ui->menu_Channels->addAction(action);
}
void MainWindow::addChannelRollup(QWidget* widget)
{
((ChannelWindow*)ui->channelDock->widget())->addRollupWidget(widget);
}
void MainWindow::addViewAction(QAction* action)
@ -201,7 +211,7 @@ void MainWindow::saveSettings(Preset* preset)
preset->setScopeConfig(m_scopeWindow->serialize());
else preset->setScopeConfig(QByteArray());
preset->clearDemods();
preset->clearChannels();
m_pluginManager->saveSettings(preset);
preset->setLayout(saveState());
@ -502,7 +512,6 @@ void MainWindow::on_action_Preferences_triggered()
preferencesDialog.exec();
}
void MainWindow::on_sampleSource_currentIndexChanged(int index)
{
m_pluginManager->selectSampleSource(ui->sampleSource->currentIndex());

View File

@ -22,16 +22,7 @@
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>
@ -52,7 +43,7 @@
<x>0</x>
<y>0</y>
<width>1012</width>
<height>24</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@ -95,9 +86,9 @@
<addaction name="separator"/>
<addaction name="action_About"/>
</widget>
<widget class="QMenu" name="menu_Demodulation">
<widget class="QMenu" name="menu_Channels">
<property name="title">
<string>&amp;Demodulation</string>
<string>&amp;Channels</string>
</property>
</widget>
<widget class="QMenu" name="menu_Window">
@ -108,7 +99,7 @@
<addaction name="menu_File"/>
<addaction name="menu_View"/>
<addaction name="menu_Acquisition"/>
<addaction name="menu_Demodulation"/>
<addaction name="menu_Channels"/>
<addaction name="menu_Options"/>
<addaction name="menu_Window"/>
<addaction name="menu_Help"/>
@ -131,16 +122,7 @@
</attribute>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout_6">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>2</number>
</property>
<property name="spacing">
@ -257,16 +239,7 @@
<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">
<property name="margin">
<number>2</number>
</property>
<item>
@ -275,7 +248,7 @@
<number>3</number>
</property>
<item>
<widget class="QToolButton" name="dcOffset">
<widget class="ButtonSwitch" name="dcOffset">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -288,13 +261,10 @@
<property name="text">
<string>DC Offset Corr</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="iqImbalance">
<widget class="ButtonSwitch" name="iqImbalance">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -307,9 +277,6 @@
<property name="text">
<string>I/Q Imbal. Corr</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -338,16 +305,7 @@
<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">
<property name="margin">
<number>2</number>
</property>
<item>
@ -360,6 +318,24 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="channelDock">
<property name="windowTitle">
<string>Channels</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="ChannelWindow" name="channelWindow">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>3</number>
</property>
<property name="margin">
<number>2</number>
</property>
</layout>
</widget>
</widget>
<action name="action_Exit">
<property name="text">
<string>E&amp;xit</string>
@ -447,6 +423,7 @@
</property>
</action>
<zorder>presetDock</zorder>
<zorder>channelDock</zorder>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
@ -462,6 +439,17 @@
<header>gui/glspectrumgui.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>ChannelWindow</class>
<extends>QWidget</extends>
<header>gui/channelwindow.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>presetTree</tabstop>

View File

@ -19,14 +19,29 @@ MessageQueue* PluginAPI::getMainWindowMessageQueue()
return m_mainWindow->getMessageQueue();
}
void PluginAPI::registerDemodulator(const QString& demodName, PluginInterface* plugin, QAction* action)
void PluginAPI::setInputGUI(QWidget* inputGUI)
{
m_pluginManager->registerDemodulator(demodName, plugin, action);
m_mainWindow->setInputGUI(inputGUI);
}
void PluginAPI::registerDemodulatorInstance(const QString& demodName, PluginGUI* pluginGUI)
void PluginAPI::registerChannel(const QString& channelName, PluginInterface* plugin, QAction* action)
{
m_pluginManager->registerDemodulatorInstance(demodName, pluginGUI);
m_pluginManager->registerChannel(channelName, plugin, action);
}
void PluginAPI::registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI)
{
m_pluginManager->registerChannelInstance(channelName, pluginGUI);
}
void PluginAPI::addChannelRollup(QWidget* pluginGUI)
{
m_pluginManager->addChannelRollup(pluginGUI);
}
void PluginAPI::removeChannelInstance(PluginGUI* pluginGUI)
{
m_pluginManager->removeChannelInstance(pluginGUI);
}
void PluginAPI::addChannelMarker(ChannelMarker* channelMarker)

View File

@ -1,15 +1,5 @@
#include "plugin/plugingui.h"
PluginGUI::PluginGUI(QWidget* parent) :
QWidget(parent)
{
}
void PluginGUI::setWidgetName(const QString& name)
{
setObjectName(name);
}
QByteArray PluginGUI::serializeGeneral() const
{
return QByteArray();

View File

@ -37,17 +37,32 @@ void PluginManager::loadPlugins()
updateSampleSourceDevices();
}
void PluginManager::registerDemodulator(const QString& demodName, PluginInterface* plugin, QAction* action)
void PluginManager::registerChannel(const QString& channelName, PluginInterface* plugin, QAction* action)
{
m_demodRegistrations.append(DemodRegistration(demodName, plugin));
m_mainWindow->addDemodCreateAction(action);
m_channelRegistrations.append(ChannelRegistration(channelName, plugin));
m_mainWindow->addChannelCreateAction(action);
}
void PluginManager::registerDemodulatorInstance(const QString& demodName, PluginGUI* pluginGUI)
void PluginManager::registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI)
{
connect(pluginGUI, SIGNAL(destroyed(QObject*)), this, SLOT(demodInstanceDestroyed(QObject*)));
m_demodInstanceRegistrations.append(DemodInstanceRegistration(demodName, pluginGUI));
renameDemodInstances();
m_channelInstanceRegistrations.append(ChannelInstanceRegistration(channelName, pluginGUI));
renameChannelInstances();
}
void PluginManager::addChannelRollup(QWidget* pluginGUI)
{
m_mainWindow->addChannelRollup(pluginGUI);
}
void PluginManager::removeChannelInstance(PluginGUI* pluginGUI)
{
for(ChannelInstanceRegistrations::iterator it = m_channelInstanceRegistrations.begin(); it != m_channelInstanceRegistrations.end(); ++it) {
if(it->m_gui == pluginGUI) {
m_channelInstanceRegistrations.erase(it);
break;
}
}
renameChannelInstances();
}
void PluginManager::registerSampleSource(const QString& sourceName, PluginInterface* plugin)
@ -59,46 +74,44 @@ void PluginManager::loadSettings(const Preset* preset)
{
qDebug("-------- [%s | %s] --------", qPrintable(preset->getGroup()), qPrintable(preset->getDescription()));
// copy currently open demods and clear list
DemodInstanceRegistrations availableDemods = m_demodInstanceRegistrations;
m_demodInstanceRegistrations.clear();
// copy currently open channels and clear list
ChannelInstanceRegistrations openChannels = m_channelInstanceRegistrations;
m_channelInstanceRegistrations.clear();
for(int i = 0; i < preset->getDemodCount(); i++) {
const Preset::DemodConfig& demodConfig = preset->getDemodConfig(i);
DemodInstanceRegistration reg;
for(int i = 0; i < preset->getChannelCount(); i++) {
const Preset::ChannelConfig& channelConfig = preset->getChannelConfig(i);
ChannelInstanceRegistration reg;
// if we have one instance available already, use it
for(int i = 0; i < availableDemods.count(); i++) {
qDebug("compare [%s] vs [%s]", qPrintable(availableDemods[i].m_demodName), qPrintable(demodConfig.m_demod));
if(availableDemods[i].m_demodName == demodConfig.m_demod) {
qDebug("demod [%s] found", qPrintable(availableDemods[i].m_demodName));
reg = availableDemods.takeAt(i);
m_demodInstanceRegistrations.append(reg);
for(int i = 0; i < openChannels.count(); i++) {
qDebug("compare [%s] vs [%s]", qPrintable(openChannels[i].m_channelName), qPrintable(channelConfig.m_channel));
if(openChannels[i].m_channelName == channelConfig.m_channel) {
qDebug("channel [%s] found", qPrintable(openChannels[i].m_channelName));
reg = openChannels.takeAt(i);
m_channelInstanceRegistrations.append(reg);
break;
}
}
// if we haven't one already, create one
if(reg.m_gui == NULL) {
for(int i = 0; i < m_demodRegistrations.count(); i++) {
if(m_demodRegistrations[i].m_demodName == demodConfig.m_demod) {
qDebug("creating new demod [%s]", qPrintable(demodConfig.m_demod));
reg = DemodInstanceRegistration(demodConfig.m_demod, m_demodRegistrations[i].m_plugin->createDemod(demodConfig.m_demod));
for(int i = 0; i < m_channelRegistrations.count(); i++) {
if(m_channelRegistrations[i].m_channelName == channelConfig.m_channel) {
qDebug("creating new channel [%s]", qPrintable(channelConfig.m_channel));
reg = ChannelInstanceRegistration(channelConfig.m_channel, m_channelRegistrations[i].m_plugin->createChannel(channelConfig.m_channel));
break;
}
}
}
if(reg.m_gui != NULL) {
reg.m_gui->deserialize(demodConfig.m_config);
reg.m_gui->raise();
}
if(reg.m_gui != NULL)
reg.m_gui->deserialize(channelConfig.m_config);
}
// everything, that is still "available" is not needed anymore
for(int i = 0; i < availableDemods.count(); i++) {
qDebug("destroying spare demod [%s]", qPrintable(availableDemods[i].m_demodName));
availableDemods[i].m_gui->destroy();
for(int i = 0; i < openChannels.count(); i++) {
qDebug("destroying spare channel [%s]", qPrintable(openChannels[i].m_channelName));
openChannels[i].m_gui->destroy();
}
renameDemodInstances();
renameChannelInstances();
if(m_sampleSourceInstance != NULL) {
m_sampleSourceInstance->deserializeGeneral(preset->getSourceGeneralConfig());
@ -116,17 +129,16 @@ void PluginManager::saveSettings(Preset* preset) const
} else {
preset->setSourceConfig(QString::null, QByteArray(), QByteArray());
}
for(int i = 0; i < m_demodInstanceRegistrations.size(); i++)
preset->addDemod(m_demodInstanceRegistrations[i].m_demodName, m_demodInstanceRegistrations[i].m_gui->serialize());
for(int i = 0; i < m_channelInstanceRegistrations.count(); i++)
preset->addChannel(m_channelInstanceRegistrations[i].m_channelName, m_channelInstanceRegistrations[i].m_gui->serialize());
}
void PluginManager::freeAll()
{
m_dspEngine->stopAcquistion();
while(!m_demodInstanceRegistrations.isEmpty()) {
DemodInstanceRegistration reg(m_demodInstanceRegistrations.takeLast());
reg.m_gui->disconnect(this);
while(!m_channelInstanceRegistrations.isEmpty()) {
ChannelInstanceRegistration reg(m_channelInstanceRegistrations.takeLast());
reg.m_gui->destroy();
}
@ -147,7 +159,7 @@ bool PluginManager::handleMessage(Message* message)
}
}
for(DemodInstanceRegistrations::iterator it = m_demodInstanceRegistrations.begin(); it != m_demodInstanceRegistrations.end(); ++it) {
for(ChannelInstanceRegistrations::iterator it = m_channelInstanceRegistrations.begin(); it != m_channelInstanceRegistrations.end(); ++it) {
if((message->destination() == NULL) || (message->destination() == it->m_gui)) {
if(it->m_gui->handleMessage(message))
return true;
@ -204,7 +216,6 @@ int PluginManager::selectSampleSource(int index)
m_sampleSource = m_sampleSourceDevices[index].m_sourceName;
m_sampleSourceInstance = m_sampleSourceDevices[index].m_plugin->createSampleSource(m_sampleSource, m_sampleSourceDevices[index].m_address);
m_mainWindow->setInputGUI(m_sampleSourceInstance);
return index;
}
@ -239,21 +250,9 @@ int PluginManager::selectSampleSource(const QString& source)
m_sampleSource = m_sampleSourceDevices[index].m_sourceName;
m_sampleSourceInstance = m_sampleSourceDevices[index].m_plugin->createSampleSource(m_sampleSource, m_sampleSourceDevices[index].m_address);
m_mainWindow->setInputGUI(m_sampleSourceInstance);
return index;
}
void PluginManager::demodInstanceDestroyed(QObject* object)
{
for(DemodInstanceRegistrations::iterator it = m_demodInstanceRegistrations.begin(); it != m_demodInstanceRegistrations.end(); ++it) {
if(it->m_gui == object) {
m_demodInstanceRegistrations.erase(it);
break;
}
}
renameDemodInstances();
}
void PluginManager::loadPlugins(const QDir& dir)
{
QDir pluginsDir(dir);
@ -273,9 +272,9 @@ void PluginManager::loadPlugins(const QDir& dir)
loadPlugins(pluginsDir.absoluteFilePath(dirName));
}
void PluginManager::renameDemodInstances()
void PluginManager::renameChannelInstances()
{
for(int i = 0; i < m_demodInstanceRegistrations.count(); i++) {
m_demodInstanceRegistrations[i].m_gui->setWidgetName(QString("%1:%2").arg(m_demodInstanceRegistrations[i].m_demodName).arg(i));
for(int i = 0; i < m_channelInstanceRegistrations.count(); i++) {
m_channelInstanceRegistrations[i].m_gui->setName(QString("%1:%2").arg(m_channelInstanceRegistrations[i].m_channelName).arg(i));
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

View File

@ -2,7 +2,6 @@
<qresource prefix="/">
<file>appicon.png</file>
<file>histogram.png</file>
<file>livespectrum.png</file>
<file>waterfall.png</file>
<file>preset-load.png</file>
<file>preset-save.png</file>
@ -10,5 +9,6 @@
<file>horizontal.png</file>
<file>vertical.png</file>
<file>logo.png</file>
<file>maxhold.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -18,7 +18,7 @@ void Preset::resetToDefaults()
m_showScope = true;
m_layout.clear();
m_spectrumConfig.clear();
m_demodConfigs.clear();
m_channelConfigs.clear();
m_source.clear();
m_sourceConfig.clear();
}
@ -39,10 +39,10 @@ QByteArray Preset::serialize() const
s.writeBlob(11, m_sourceGeneralConfig);
s.writeBlob(12, m_sourceConfig);
s.writeS32(100, m_demodConfigs.size());
for(int i = 0; i < m_demodConfigs.size(); i++) {
s.writeString(101 + i * 2, m_demodConfigs[i].m_demod);
s.writeBlob(102 + i * 2, m_demodConfigs[i].m_config);
s.writeS32(100, m_channelConfigs.size());
for(int i = 0; i < m_channelConfigs.size(); i++) {
s.writeString(101 + i * 2, m_channelConfigs[i].m_channel);
s.writeBlob(102 + i * 2, m_channelConfigs[i].m_config);
}
return s.final();
@ -71,14 +71,14 @@ bool Preset::deserialize(const QByteArray& data)
d.readBlob(11, &m_sourceGeneralConfig);
d.readBlob(12, &m_sourceConfig);
qint32 demodCount = 0;
d.readS32(100, &demodCount, 0);
for(int i = 0; i < demodCount; i++) {
QString demod;
qint32 channelCount = 0;
d.readS32(100, &channelCount, 0);
for(int i = 0; i < channelCount; i++) {
QString channel;
QByteArray config;
d.readString(101 + i * 2, &demod, "unknown-demod");
d.readString(101 + i * 2, &channel, "unknown-channel");
d.readBlob(102 + i * 2, &config);
m_demodConfigs.append(DemodConfig(demod, config));
m_channelConfigs.append(ChannelConfig(channel, config));
}
return true;
} else {