New Jogdial Controller feature plugin. Implements #1088

pull/1108/head
f4exb 2022-01-06 22:47:41 +01:00
rodzic 7142ef0b0d
commit 128dd03684
123 zmienionych plików z 3333 dodań i 22 usunięć

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 12 KiB

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 120 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 162 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 978 KiB

Wyświetl plik

@ -100,6 +100,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "BeamSteeringCWMod"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
uint32_t getBasebandSampleRate() const { return m_basebandSampleRate; }
virtual QByteArray serialize() const;

Wyświetl plik

@ -101,6 +101,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "Interferometer"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
uint32_t getDeviceSampleRate() const { return m_deviceSampleRate; }
virtual QByteArray serialize() const;

Wyświetl plik

@ -152,6 +152,13 @@ bool ChannelAnalyzer::handleMessage(const Message& cmd)
}
}
void ChannelAnalyzer::setCenterFrequency(qint64 frequency)
{
ChannelAnalyzerSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings);
}
void ChannelAnalyzer::applySettings(const ChannelAnalyzerSettings& settings, bool force)
{
qDebug() << "ChannelAnalyzer::applySettings:"

Wyświetl plik

@ -85,6 +85,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = objectName(); }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const { return QByteArray(); }
virtual bool deserialize(const QByteArray& data) { (void) data; return false; }

Wyświetl plik

@ -262,6 +262,19 @@ void ADSBDemod::applySettings(const ADSBDemodSettings& settings, bool force)
m_settings = settings;
}
void ADSBDemod::setCenterFrequency(qint64 frequency)
{
ADSBDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureADSBDemod *msgToGUI = MsgConfigureADSBDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
QByteArray ADSBDemod::serialize() const
{
return m_settings.serialize();

Wyświetl plik

@ -76,6 +76,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -218,6 +218,19 @@ ScopeVis *AISDemod::getScopeSink()
return m_basebandSink->getScopeSink();
}
void AISDemod::setCenterFrequency(qint64 frequency)
{
AISDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAISDemod *msgToGUI = MsgConfigureAISDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void AISDemod::applySettings(const AISDemodSettings& settings, bool force)
{
qDebug() << "AISDemod::applySettings:"

Wyświetl plik

@ -104,7 +104,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -151,6 +151,19 @@ bool AMDemod::handleMessage(const Message& cmd)
}
}
void AMDemod::setCenterFrequency(qint64 frequency)
{
AMDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAMDemod *msgToGUI = MsgConfigureAMDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
{
qDebug() << "AMDemod::applySettings:"

Wyświetl plik

@ -74,6 +74,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -210,6 +210,19 @@ bool APTDemod::handleMessage(const Message& cmd)
}
}
void APTDemod::setCenterFrequency(qint64 frequency)
{
APTDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAPTDemod *msgToGUI = MsgConfigureAPTDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void APTDemod::applySettings(const APTDemodSettings& settings, bool force)
{
qDebug() << "APTDemod::applySettings:"

Wyświetl plik

@ -187,7 +187,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -129,6 +129,19 @@ bool ATVDemod::handleMessage(const Message& cmd)
}
}
void ATVDemod::setCenterFrequency(qint64 frequency)
{
ATVDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (getMessageQueueToGUI())
{
MsgConfigureATVDemod *msg = MsgConfigureATVDemod::create(settings, false);
getMessageQueueToGUI()->push(msg);
}
}
void ATVDemod::applySettings(const ATVDemodSettings& settings, bool force)
{
qDebug() << "ATVDemod::applySettings:"

Wyświetl plik

@ -74,6 +74,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = objectName(); }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const { return QByteArray(); }
virtual bool deserialize(const QByteArray& data) { (void) data; return false; }

Wyświetl plik

@ -143,6 +143,19 @@ bool BFMDemod::handleMessage(const Message& cmd)
}
}
void BFMDemod::setCenterFrequency(qint64 frequency)
{
BFMDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureBFMDemod *msgToGUI = MsgConfigureBFMDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
{
qDebug() << "BFMDemod::applySettings: MsgConfigureBFMDemod:"

Wyświetl plik

@ -82,6 +82,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -294,6 +294,19 @@ bool ChirpChatDemod::handleMessage(const Message& cmd)
}
}
void ChirpChatDemod::setCenterFrequency(qint64 frequency)
{
ChirpChatDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureChirpChatDemod *msgToGUI = MsgConfigureChirpChatDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
QByteArray ChirpChatDemod::serialize() const
{
return m_settings.serialize();

Wyświetl plik

@ -211,7 +211,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -272,6 +272,19 @@ bool DABDemod::handleMessage(const Message& cmd)
}
}
void DABDemod::setCenterFrequency(qint64 frequency)
{
DABDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureDABDemod *msgToGUI = MsgConfigureDABDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void DABDemod::applySettings(const DABDemodSettings& settings, bool force)
{
qDebug() << "DABDemod::applySettings:"

Wyświetl plik

@ -324,7 +324,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -130,6 +130,19 @@ bool DATVDemod::handleMessage(const Message& cmd)
}
}
void DATVDemod::setCenterFrequency(qint64 frequency)
{
DATVDemodSettings settings = m_settings;
settings.m_centerFrequency = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureDATVDemod *msgToGUI = MsgConfigureDATVDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void DATVDemod::applySettings(const DATVDemodSettings& settings, bool force)
{
QString debugMsg = tr("DATVDemod::applySettings: force: %1").arg(force);

Wyświetl plik

@ -49,6 +49,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = objectName(); }
virtual qint64 getCenterFrequency() const { return m_settings.m_centerFrequency; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const { return QByteArray(); }
virtual bool deserialize(const QByteArray& data) { (void) data; return false; }

Wyświetl plik

@ -150,6 +150,19 @@ bool DSDDemod::handleMessage(const Message& cmd)
}
}
void DSDDemod::setCenterFrequency(qint64 frequency)
{
DSDDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureDSDDemod *msgToGUI = MsgConfigureDSDDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force)
{
qDebug() << "DSDDemod::applySettings: "

Wyświetl plik

@ -75,6 +75,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -144,6 +144,18 @@ bool FreeDVDemod::handleMessage(const Message& cmd)
}
}
void FreeDVDemod::setCenterFrequency(qint64 frequency)
{
FreeDVDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureFreeDVDemod *msgToGUI = MsgConfigureFreeDVDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void FreeDVDemod::applySettings(const FreeDVDemodSettings& settings, bool force)
{

Wyświetl plik

@ -88,6 +88,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -147,6 +147,19 @@ bool NFMDemod::handleMessage(const Message& cmd)
}
}
void NFMDemod::setCenterFrequency(qint64 frequency)
{
NFMDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureNFMDemod *msgToGUI = MsgConfigureNFMDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
{
qDebug() << "NFMDemod::applySettings:"

Wyświetl plik

@ -74,6 +74,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -219,6 +219,19 @@ bool PacketDemod::handleMessage(const Message& cmd)
}
}
void PacketDemod::setCenterFrequency(qint64 frequency)
{
PacketDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigurePacketDemod *msgToGUI = MsgConfigurePacketDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void PacketDemod::applySettings(const PacketDemodSettings& settings, bool force)
{
qDebug() << "PacketDemod::applySettings:"

Wyświetl plik

@ -78,7 +78,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -189,6 +189,19 @@ ScopeVis *PagerDemod::getScopeSink()
return m_basebandSink->getScopeSink();
}
void PagerDemod::setCenterFrequency(qint64 frequency)
{
PagerDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigurePagerDemod *msgToGUI = MsgConfigurePagerDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void PagerDemod::applySettings(const PagerDemodSettings& settings, bool force)
{
qDebug() << "PagerDemod::applySettings:"

Wyświetl plik

@ -119,7 +119,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -146,6 +146,19 @@ bool SSBDemod::handleMessage(const Message& cmd)
}
}
void SSBDemod::setCenterFrequency(qint64 frequency)
{
SSBDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureSSBDemod *msgToGUI = MsgConfigureSSBDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
{
qDebug() << "SSBDemod::applySettings:"

Wyświetl plik

@ -77,6 +77,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -76,6 +76,7 @@ public:
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual void setCenterFrequency(qint64) {}
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -191,6 +191,19 @@ bool VORDemodSC::handleMessage(const Message& cmd)
}
}
void VORDemodSC::setCenterFrequency(qint64 frequency)
{
VORDemodSCSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureVORDemod *msgToGUI = MsgConfigureVORDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void VORDemodSC::applySettings(const VORDemodSCSettings& settings, bool force)
{
qDebug() << "VORDemodSC::applySettings:"

Wyświetl plik

@ -75,7 +75,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -148,6 +148,19 @@ bool WFMDemod::handleMessage(const Message& cmd)
}
}
void WFMDemod::setCenterFrequency(qint64 frequency)
{
WFMDemodSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureWFMDemod *msgToGUI = MsgConfigureWFMDemod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force)
{
qDebug() << "WFMDemod::applySettings:"

Wyświetl plik

@ -73,6 +73,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -94,6 +94,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "File Sink"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -163,6 +163,19 @@ bool FreqTracker::handleMessage(const Message& cmd)
}
}
void FreqTracker::setCenterFrequency(qint64 frequency)
{
FreqTrackerSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureFreqTracker *msgToGUI = MsgConfigureFreqTracker::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force)
{
if (!settings.m_tracking)

Wyświetl plik

@ -73,6 +73,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -95,6 +95,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "Local Sink"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -99,6 +99,19 @@ uint32_t NoiseFigure::getNumberOfDeviceStreams() const
return m_deviceAPI->getNbSourceStreams();
}
void NoiseFigure::setCenterFrequency(qint64 frequency)
{
NoiseFigureSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureNoiseFigure *msgToGUI = MsgConfigureNoiseFigure::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void NoiseFigure::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
{
(void) firstOfBurst;

Wyświetl plik

@ -183,7 +183,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -155,6 +155,19 @@ void RadioAstronomy::stop()
m_workerThread.wait();
}
void RadioAstronomy::setCenterFrequency(qint64 frequency)
{
RadioAstronomySettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureRadioAstronomy *msgToGUI = MsgConfigureRadioAstronomy::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool RadioAstronomy::handleMessage(const Message& cmd)
{
if (MsgConfigureRadioAstronomy::match(cmd))

Wyświetl plik

@ -321,7 +321,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -117,6 +117,19 @@ void RadioClock::stop()
m_thread.wait();
}
void RadioClock::setCenterFrequency(qint64 frequency)
{
RadioClockSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureRadioClock *msgToGUI = MsgConfigureRadioClock::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool RadioClock::handleMessage(const Message& cmd)
{
if (MsgConfigureRadioClock::match(cmd))

Wyświetl plik

@ -123,7 +123,8 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual const QString& getURI() const { return getName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -75,6 +75,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "Remote Sink"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -94,6 +94,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "SigMF File Sink"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -134,6 +134,19 @@ bool UDPSink::handleMessage(const Message& cmd)
}
}
void UDPSink::setCenterFrequency(qint64 frequency)
{
UDPSinkSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureUDPSink *msgToGUI = MsgConfigureUDPSink::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void UDPSink::applySettings(const UDPSinkSettings& settings, bool force)
{
qDebug() << "UDPSink::applySettings:"

Wyświetl plik

@ -81,6 +81,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -177,6 +177,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual void setCenterFrequency(qint64) {}
virtual int getNbSinkStreams() const { return 0; }
virtual int getNbSourceStreams() const { return 1; }

Wyświetl plik

@ -92,6 +92,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "Local Sink"; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -149,6 +149,19 @@ bool IEEE_802_15_4_Mod::handleMessage(const Message& cmd)
}
}
void IEEE_802_15_4_Mod::setCenterFrequency(qint64 frequency)
{
IEEE_802_15_4_ModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureIEEE_802_15_4_Mod *msgToGUI = MsgConfigureIEEE_802_15_4_Mod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void IEEE_802_15_4_Mod::applySettings(const IEEE_802_15_4_ModSettings& settings, bool force)
{
qDebug() << "IEEE_802_15_4_Mod::applySettings:"

Wyświetl plik

@ -101,6 +101,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -109,6 +109,19 @@ void AISMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void AISMod::setCenterFrequency(qint64 frequency)
{
AISModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAISMod *msgToGUI = MsgConfigureAISMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool AISMod::handleMessage(const Message& cmd)
{
if (MsgConfigureAISMod::match(cmd))

Wyświetl plik

@ -162,6 +162,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -112,6 +112,19 @@ void AMMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void AMMod::setCenterFrequency(qint64 frequency)
{
AMModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAMMod *msgToGUI = MsgConfigureAMMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool AMMod::handleMessage(const Message& cmd)
{
if (MsgConfigureAMMod::match(cmd))

Wyświetl plik

@ -184,6 +184,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -211,6 +211,19 @@ bool ATVMod::handleMessage(const Message& cmd)
}
}
void ATVMod::setCenterFrequency(qint64 frequency)
{
ATVModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureATVMod *msgToGUI = MsgConfigureATVMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void ATVMod::applySettings(const ATVModSettings& settings, bool force)
{
qDebug() << "ATVMod::applySettings:"

Wyświetl plik

@ -256,6 +256,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -136,6 +136,19 @@ bool ChirpChatMod::handleMessage(const Message& cmd)
}
}
void ChirpChatMod::setCenterFrequency(qint64 frequency)
{
ChirpChatModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureChirpChatMod *msgToGUI = MsgConfigureChirpChatMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void ChirpChatMod::applySettings(const ChirpChatModSettings& settings, bool force)
{
qDebug() << "ChirpChatMod::applySettings:"

Wyświetl plik

@ -99,6 +99,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -199,6 +199,17 @@ bool DATVMod::handleMessage(const Message& cmd)
}
}
void DATVMod::setCenterFrequency(qint64 frequency)
{
DATVModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) {
m_guiMessageQueue->push(MsgConfigureDATVMod::create(settings, false));
}
}
void DATVMod::applySettings(const DATVModSettings& settings, bool force)
{
qDebug() << "DATVMod::applySettings:"
@ -354,8 +365,9 @@ int DATVMod::webapiSettingsPutPatch(
MsgConfigureDATVMod *msg = MsgConfigureDATVMod::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue)
if (m_guiMessageQueue) {
m_guiMessageQueue->push(MsgConfigureDATVMod::create(settings, force));
}
if (channelSettingsKeys.contains("tsFileName"))
{

Wyświetl plik

@ -212,6 +212,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -111,6 +111,19 @@ void FreeDVMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void FreeDVMod::setCenterFrequency(qint64 frequency)
{
FreeDVModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureFreeDVMod *msgToGUI = MsgConfigureFreeDVMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool FreeDVMod::handleMessage(const Message& cmd)
{
if (MsgConfigureFreeDVMod::match(cmd))

Wyświetl plik

@ -188,6 +188,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -108,6 +108,19 @@ void NFMMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void NFMMod::setCenterFrequency(qint64 frequency)
{
NFMModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureNFMMod *msgToGUI = MsgConfigureNFMMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool NFMMod::handleMessage(const Message& cmd)
{
if (MsgConfigureNFMMod::match(cmd))

Wyświetl plik

@ -184,6 +184,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -154,6 +154,19 @@ bool PacketMod::handleMessage(const Message& cmd)
}
}
void PacketMod::setCenterFrequency(qint64 frequency)
{
PacketModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigurePacketMod *msgToGUI = MsgConfigurePacketMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
void PacketMod::applySettings(const PacketModSettings& settings, bool force)
{
qDebug() << "PacketMod::applySettings:"

Wyświetl plik

@ -152,6 +152,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -109,6 +109,19 @@ void SSBMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void SSBMod::setCenterFrequency(qint64 frequency)
{
SSBModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureSSBMod *msgToGUI = MsgConfigureSSBMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool SSBMod::handleMessage(const Message& cmd)
{
if (MsgConfigureSSBMod::match(cmd))

Wyświetl plik

@ -186,6 +186,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -106,6 +106,19 @@ void WFMMod::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void WFMMod::setCenterFrequency(qint64 frequency)
{
WFMModSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureWFMMod *msgToGUI = MsgConfigureWFMMod::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool WFMMod::handleMessage(const Message& cmd)
{
if (MsgConfigureWFMMod::match(cmd))

Wyświetl plik

@ -184,6 +184,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -188,6 +188,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_frequencyOffset; }
virtual void setCenterFrequency(qint64) {}
virtual int getNbSinkStreams() const { return 0; }
virtual int getNbSourceStreams() const { return 1; }

Wyświetl plik

@ -91,6 +91,19 @@ void UDPSource::pull(SampleVector::iterator& begin, unsigned int nbSamples)
m_basebandSource->pull(begin, nbSamples);
}
void UDPSource::setCenterFrequency(qint64 frequency)
{
UDPSourceSettings settings = m_settings;
settings.m_inputFrequencyOffset = frequency;
applySettings(settings, false);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureUDPSource *msgToGUI = MsgConfigureUDPSource::create(settings, false);
m_guiMessageQueue->push(msgToGUI);
}
}
bool UDPSource::handleMessage(const Message& cmd)
{
if (MsgConfigureChannelizer::match(cmd))

Wyświetl plik

@ -105,6 +105,7 @@ public:
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual void setCenterFrequency(qint64 frequency);
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);

Wyświetl plik

@ -24,6 +24,7 @@ if (NOT SERVER_MODE)
if (SGP4_FOUND AND Qt5Positioning_FOUND AND Qt5Charts_FOUND AND Qt5TextToSpeech_FOUND)
add_subdirectory(satellitetracker)
endif()
add_subdirectory(jogdialcontroller)
else()
if (SGP4_FOUND AND Qt5Positioning_FOUND AND Qt5Charts_FOUND)
add_subdirectory(satellitetracker)

Wyświetl plik

@ -213,7 +213,7 @@ bool DemodAnalyzer::deserialize(const QByteArray& data)
void DemodAnalyzer::applySettings(const DemodAnalyzerSettings& settings, bool force)
{
qDebug() << "DemodAnalyzer::applySettings:"
<< " m_channelIndex: " << settings.m_log2Decim
<< " m_log2Decim: " << settings.m_log2Decim
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_useReverseAPI: " << settings.m_useReverseAPI

Wyświetl plik

@ -0,0 +1,54 @@
project(jogdialcontroller)
set(jogdialcontroller_SOURCES
jogdialcontroller.cpp
jogdialcontrollersettings.cpp
jogdialcontrollerplugin.cpp
jogdialcontrollerwebapiadapter.cpp
)
set(jogdialcontroller_HEADERS
jogdialcontroller.h
jogdialcontrollersettings.h
jogdialcontrollerplugin.h
jogdialcontrollerwebapiadapter.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
if(NOT SERVER_MODE)
set(jogdialcontroller_SOURCES
${jogdialcontroller_SOURCES}
jogdialcontrollergui.cpp
jogdialcontrollergui.ui
)
set(jogdialcontroller_HEADERS
${jogdialcontroller_HEADERS}
jogdialcontrollergui.h
)
set(TARGET_NAME jogdialcontroller)
set(TARGET_LIB "Qt5::Widgets")
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME jogdialcontrollersrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${jogdialcontroller_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt5::Core
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})

Wyświetl plik

@ -0,0 +1,648 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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 <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include "SWGFeatureSettings.h"
#include "SWGFeatureActions.h"
#include "SWGDeviceState.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "dsp/dspdevicesourceengine.h"
#include "dsp/dspdevicesinkengine.h"
#include "dsp/devicesamplesource.h"
#include "dsp/devicesamplesink.h"
#include "device/deviceset.h"
#include "channel/channelapi.h"
#include "device/deviceapi.h"
#include "commands/commandkeyreceiver.h"
#include "maincore.h"
#include "jogdialcontroller.h"
MESSAGE_CLASS_DEFINITION(JogdialController::MsgConfigureJogdialController, Message)
MESSAGE_CLASS_DEFINITION(JogdialController::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(JogdialController::MsgRefreshChannels, Message)
MESSAGE_CLASS_DEFINITION(JogdialController::MsgReportChannels, Message)
MESSAGE_CLASS_DEFINITION(JogdialController::MsgReportControl, Message)
MESSAGE_CLASS_DEFINITION(JogdialController::MsgSelectChannel, Message)
const char* const JogdialController::m_featureIdURI = "sdrangel.feature.jogdialcontroller";
const char* const JogdialController::m_featureId = "JogdialController";
JogdialController::JogdialController(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_selectedDevice(nullptr),
m_selectedChannel(nullptr),
m_selectedIndex(-1),
m_deviceElseChannelControl(true),
m_multiplier(1)
{
qDebug("JogdialController::JogdialController: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
m_state = StIdle;
m_errorMessage = "JogdialController error";
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
connect(&m_repeatTimer, SIGNAL(timeout()), this, SLOT(handleRepeat()));
}
JogdialController::~JogdialController()
{
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
}
void JogdialController::start()
{
qDebug("JogdialController::start");
m_state = StRunning;
}
void JogdialController::stop()
{
qDebug("JogdialController::stop");
m_state = StIdle;
}
bool JogdialController::handleMessage(const Message& cmd)
{
if (MsgConfigureJogdialController::match(cmd))
{
MsgConfigureJogdialController& cfg = (MsgConfigureJogdialController&) cmd;
qDebug() << "JogdialController::handleMessage: MsgConfigureJogdialController";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (MsgStartStop::match(cmd))
{
MsgStartStop& cfg = (MsgStartStop&) cmd;
qDebug() << "JogdialController::handleMessage: MsgStartStop: start:" << cfg.getStartStop();
if (cfg.getStartStop()) {
start();
} else {
stop();
}
return true;
}
else if (MsgRefreshChannels::match(cmd))
{
qDebug() << "JogdialController::handleMessage: MsgRefreshChannels";
updateChannels();
return true;
}
else if (MsgSelectChannel::match(cmd))
{
MsgSelectChannel& cfg = (MsgSelectChannel&) cmd;
int index = cfg.getIndex();
if ((index >= 0) && (index < m_availableChannels.size()))
{
DeviceAPI *selectedDevice = m_availableChannels[cfg.getIndex()].m_deviceAPI;
ChannelAPI *selectedChannel = m_availableChannels[cfg.getIndex()].m_channelAPI;
QString channelId;
selectedChannel->getIdentifier(channelId);
qDebug() << "JogdialController::handleMessage: MsgSelectChannel"
<< "device:" << selectedDevice->getHardwareId()
<< "channel:" << channelId;
m_selectedDevice = selectedDevice;
m_selectedChannel = selectedChannel;
m_selectedIndex = index;
}
else
{
qWarning("JogdialController::handleMessage: MsgSelectChannel: index out of range: %d", index);
}
return true;
}
else
{
return false;
}
}
QByteArray JogdialController::serialize() const
{
return m_settings.serialize();
}
bool JogdialController::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
MsgConfigureJogdialController *msg = MsgConfigureJogdialController::create(m_settings, true);
m_inputMessageQueue.push(msg);
return true;
}
else
{
m_settings.resetToDefaults();
MsgConfigureJogdialController *msg = MsgConfigureJogdialController::create(m_settings, true);
m_inputMessageQueue.push(msg);
return false;
}
}
void JogdialController::applySettings(const JogdialControllerSettings& settings, bool force)
{
qDebug() << "JogdialController::applySettings:"
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIPort: " << settings.m_reverseAPIPort
<< " m_reverseAPIFeatureSetIndex: " << settings.m_reverseAPIFeatureSetIndex
<< " m_reverseAPIFeatureIndex: " << settings.m_reverseAPIFeatureIndex
<< " force: " << force;
QList<QString> reverseAPIKeys;
if ((m_settings.m_title != settings.m_title) || force) {
reverseAPIKeys.append("title");
}
if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) {
reverseAPIKeys.append("rgbColor");
}
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_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) ||
(m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex);
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
}
void JogdialController::updateChannels()
{
MainCore *mainCore = MainCore::instance();
// MessagePipes& messagePipes = mainCore->getMessagePipes();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
std::vector<DeviceSet*>::const_iterator it = deviceSets.begin();
m_availableChannels.clear();
int deviceIndex = 0;
for (; it != deviceSets.end(); ++it, deviceIndex++)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine;
DeviceAPI *device = (*it)->m_deviceAPI;
device->getHardwareId();
if (deviceSourceEngine || deviceSinkEngine)
{
// DeviceSampleSource *deviceSource = deviceSourceEngine->getSource();
// quint64 deviceCenterFrequency = deviceSource->getCenterFrequency();
// int basebandSampleRate = deviceSource->getSampleRate();
for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = (*it)->getChannelAt(chi);
QString channelId;
channel->getIdentifier(channelId);
JogdialControllerSettings::AvailableChannel availableChannel =
JogdialControllerSettings::AvailableChannel{
deviceSinkEngine != nullptr,
deviceIndex,
chi,
device,
channel,
device->getHardwareId(),
channelId
};
m_availableChannels.push_back(availableChannel);
}
}
}
if (getMessageQueueToGUI())
{
MsgReportChannels *msgToGUI = MsgReportChannels::create();
QList<JogdialControllerSettings::AvailableChannel>& msgAvailableChannels = msgToGUI->getAvailableChannels();
msgAvailableChannels = m_availableChannels;
getMessageQueueToGUI()->push(msgToGUI);
}
}
void JogdialController::channelUp()
{
if ((m_selectedIndex < 0) || (m_availableChannels.size() == 0)) {
return;
}
m_selectedIndex++;
if (m_selectedIndex >= m_availableChannels.size()) {
m_selectedIndex = 0;
}
m_selectedDevice = m_availableChannels.at(m_selectedIndex).m_deviceAPI;
m_selectedChannel = m_availableChannels.at(m_selectedIndex).m_channelAPI;
if (getMessageQueueToGUI())
{
MsgSelectChannel *msgToGUI = MsgSelectChannel::create(m_selectedIndex);
getMessageQueueToGUI()->push(msgToGUI);
}
}
void JogdialController::channelDown()
{
if ((m_selectedIndex < 0) || (m_availableChannels.size() == 0)) {
return;
}
m_selectedIndex--;
if (m_selectedIndex < 0) {
m_selectedIndex = m_availableChannels.size() - 1;
}
m_selectedDevice = m_availableChannels.at(m_selectedIndex).m_deviceAPI;
m_selectedChannel = m_availableChannels.at(m_selectedIndex).m_channelAPI;
if (getMessageQueueToGUI())
{
MsgSelectChannel *msgToGUI = MsgSelectChannel::create(m_selectedIndex);
getMessageQueueToGUI()->push(msgToGUI);
}
}
int JogdialController::webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
getFeatureStateStr(*response.getState());
MsgStartStop *msg = MsgStartStop::create(run);
getInputMessageQueue()->push(msg);
return 202;
}
int JogdialController::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setJogdialControllerSettings(new SWGSDRangel::SWGJogdialControllerSettings());
response.getJogdialControllerSettings()->init();
webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int JogdialController::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
JogdialControllerSettings settings = m_settings;
webapiUpdateFeatureSettings(settings, featureSettingsKeys, response);
MsgConfigureJogdialController *msg = MsgConfigureJogdialController::create(settings, force);
m_inputMessageQueue.push(msg);
qDebug("JogdialController::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureJogdialController *msgToGUI = MsgConfigureJogdialController::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatFeatureSettings(response, settings);
return 200;
}
void JogdialController::webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const JogdialControllerSettings& settings)
{
if (response.getJogdialControllerSettings()->getTitle()) {
*response.getJogdialControllerSettings()->getTitle() = settings.m_title;
} else {
response.getJogdialControllerSettings()->setTitle(new QString(settings.m_title));
}
response.getJogdialControllerSettings()->setRgbColor(settings.m_rgbColor);
response.getJogdialControllerSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getJogdialControllerSettings()->getReverseApiAddress()) {
*response.getJogdialControllerSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getJogdialControllerSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getJogdialControllerSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getJogdialControllerSettings()->setReverseApiFeatureSetIndex(settings.m_reverseAPIFeatureSetIndex);
response.getJogdialControllerSettings()->setReverseApiFeatureIndex(settings.m_reverseAPIFeatureIndex);
}
void JogdialController::webapiUpdateFeatureSettings(
JogdialControllerSettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response)
{
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getJogdialControllerSettings()->getTitle();
}
if (featureSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getJogdialControllerSettings()->getRgbColor();
}
if (featureSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getJogdialControllerSettings()->getUseReverseApi() != 0;
}
if (featureSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getJogdialControllerSettings()->getReverseApiAddress();
}
if (featureSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getJogdialControllerSettings()->getReverseApiPort();
}
if (featureSettingsKeys.contains("reverseAPIFeatureSetIndex")) {
settings.m_reverseAPIFeatureSetIndex = response.getJogdialControllerSettings()->getReverseApiFeatureSetIndex();
}
if (featureSettingsKeys.contains("reverseAPIFeatureIndex")) {
settings.m_reverseAPIFeatureIndex = response.getJogdialControllerSettings()->getReverseApiFeatureIndex();
}
}
void JogdialController::webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const JogdialControllerSettings& settings, bool force)
{
SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings();
// swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet());
// swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex());
swgFeatureSettings->setFeatureType(new QString("JogdialAnalyzer"));
swgFeatureSettings->setJogdialControllerSettings(new SWGSDRangel::SWGJogdialControllerSettings());
SWGSDRangel::SWGJogdialControllerSettings *swgJogdialControllerSettings = swgFeatureSettings->getJogdialControllerSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (featureSettingsKeys.contains("title") || force) {
swgJogdialControllerSettings->setTitle(new QString(settings.m_title));
}
if (featureSettingsKeys.contains("rgbColor") || force) {
swgJogdialControllerSettings->setRgbColor(settings.m_rgbColor);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIFeatureSetIndex)
.arg(settings.m_reverseAPIFeatureIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgFeatureSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgFeatureSettings;
}
void JogdialController::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "JogdialController::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("JogdialController::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}
void JogdialController::handleChannelMessageQueue(MessageQueue* messageQueue)
{
Message* message;
while ((message = messageQueue->pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}
void JogdialController::commandKeyPressed(Qt::Key key, Qt::KeyboardModifiers keyModifiers, bool release)
{
(void) release;
if (key == Qt::Key_C)
{
m_deviceElseChannelControl = false;
if (m_guiMessageQueue) {
m_guiMessageQueue->push(MsgReportControl::create(false));
}
}
else if (key == Qt::Key_D)
{
m_deviceElseChannelControl = true;
if (m_guiMessageQueue) {
m_guiMessageQueue->push(MsgReportControl::create(true));
}
}
else if (key == Qt::Key_Left)
{
channelDown();
}
else if (key == Qt::Key_Right)
{
channelUp();
}
else if (key == Qt::Key_Up)
{
m_repeatTimer.stop();
if (keyModifiers == Qt::NoModifier) {
stepFrequency(1);
} else if (keyModifiers == Qt::ControlModifier) {
stepFrequency(10);
} else if (keyModifiers == Qt::ShiftModifier) {
stepFrequency(100);
} else if (keyModifiers == (Qt::ControlModifier | Qt::ShiftModifier)) {
stepFrequency(1000);
}
}
else if (key == Qt::Key_Down)
{
m_repeatTimer.stop();
if (keyModifiers == Qt::NoModifier) {
stepFrequency(-1);
} else if (keyModifiers == Qt::ControlModifier) {
stepFrequency(-10);
} else if (keyModifiers == Qt::ShiftModifier) {
stepFrequency(-100);
} else if (keyModifiers == (Qt::ControlModifier | Qt::ShiftModifier)) {
stepFrequency(-1000);
}
}
else if (key == Qt::Key_Home)
{
resetChannelFrequency();
}
else if (key == Qt::Key_0)
{
m_repeatTimer.stop();
}
else if (key == Qt::Key_1)
{
m_multiplier = 1;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_2)
{
m_multiplier = 10;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_3)
{
m_multiplier = 100;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_4)
{
m_multiplier = 1000;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_5)
{
m_multiplier = 10000;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_6)
{
m_multiplier = 100000;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_7)
{
m_multiplier = 1000000;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_Exclam)
{
m_multiplier = -1;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_At)
{
m_multiplier = -10;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_NumberSign)
{
m_multiplier = -100;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_Dollar)
{
m_multiplier = -1000;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_Percent)
{
m_multiplier = -10000;
m_repeatTimer.start(m_repeatms);
}
else if ((key == Qt::Key_Dead_Circumflex) || (key == Qt::Key_AsciiCircum))
{
m_multiplier = -100000;
m_repeatTimer.start(m_repeatms);
}
else if (key == Qt::Key_Ampersand)
{
m_multiplier = -1000000;
m_repeatTimer.start(m_repeatms);
}
}
void JogdialController::resetChannelFrequency()
{
if (m_selectedChannel) {
m_selectedChannel->setCenterFrequency(0);
}
}
void JogdialController::stepFrequency(int step)
{
qDebug("JogdialController::stepFrequency: step: %d", step);
if (m_deviceElseChannelControl)
{
if (m_selectedDevice)
{
DSPDeviceSourceEngine *sourceEngine = m_selectedDevice->getDeviceSourceEngine();
DSPDeviceSinkEngine *sinkEngine = m_selectedDevice->getDeviceSinkEngine();
if (sourceEngine)
{
quint64 frequency = sourceEngine->getSource()->getCenterFrequency();
qDebug("JogdialController::stepFrequency: frequency: %llu", frequency);
sourceEngine->getSource()->setCenterFrequency(frequency + step*1000LL);
}
if (sinkEngine)
{
quint64 frequency = sinkEngine->getSink()->getCenterFrequency();
sinkEngine->getSink()->setCenterFrequency(frequency + step*1000LL);
}
}
}
else
{
if (m_selectedChannel)
{
qint64 frequency = m_selectedChannel->getCenterFrequency();
m_selectedChannel->setCenterFrequency(frequency + step);
}
}
}
void JogdialController::handleRepeat()
{
stepFrequency(m_multiplier);
}

Wyświetl plik

@ -0,0 +1,223 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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_FEATURE_JOGDIALCONTROLLER_H_
#define INCLUDE_FEATURE_JOGDIALCONTROLLER_H_
#include <QList>
#include <QNetworkRequest>
#include <QTimer>
#include "feature/feature.h"
#include "util/message.h"
#include "jogdialcontrollersettings.h"
class WebAPIAdapterInterface;
class QNetworkAccessManager;
class QNetworkReply;
namespace SWGSDRangel {
class SWGDeviceState;
}
class JogdialController : public Feature
{
Q_OBJECT
public:
class MsgConfigureJogdialController : public Message {
MESSAGE_CLASS_DECLARATION
public:
const JogdialControllerSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureJogdialController* create(const JogdialControllerSettings& settings, bool force) {
return new MsgConfigureJogdialController(settings, force);
}
private:
JogdialControllerSettings m_settings;
bool m_force;
MsgConfigureJogdialController(const JogdialControllerSettings& 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 MsgRefreshChannels : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgRefreshChannels* create() {
return new MsgRefreshChannels();
}
protected:
MsgRefreshChannels() :
Message()
{ }
};
class MsgReportChannels : public Message {
MESSAGE_CLASS_DECLARATION
public:
QList<JogdialControllerSettings::AvailableChannel>& getAvailableChannels() { return m_availableChannels; }
static MsgReportChannels* create() {
return new MsgReportChannels();
}
private:
QList<JogdialControllerSettings::AvailableChannel> m_availableChannels;
MsgReportChannels() :
Message()
{}
};
class MsgSelectChannel : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getIndex() const { return m_index; }
static MsgSelectChannel* create(int index) {
return new MsgSelectChannel(index);
}
protected:
int m_index;
MsgSelectChannel(int index) :
Message(),
m_index(index)
{ }
};
class MsgReportControl : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getDeviceElseChannel() const { return m_deviceElseChannel; }
static MsgReportControl* create(bool deviceElseChannel) {
return new MsgReportControl(deviceElseChannel);
}
protected:
bool m_deviceElseChannel;
MsgReportControl(bool deviceElseChannel) :
Message(),
m_deviceElseChannel(deviceElseChannel)
{ }
};
JogdialController(WebAPIAdapterInterface *webAPIAdapterInterface);
virtual ~JogdialController();
virtual void destroy() { delete this; }
virtual bool handleMessage(const Message& cmd);
virtual void getIdentifier(QString& id) const { id = objectName(); }
virtual void getTitle(QString& title) const { title = m_settings.m_title; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
void resetChannelFrequency();
void stepFrequency(int step);
static void webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const JogdialControllerSettings& settings);
static void webapiUpdateFeatureSettings(
JogdialControllerSettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response);
static const char* const m_featureIdURI;
static const char* const m_featureId;
public slots:
void commandKeyPressed(Qt::Key key, Qt::KeyboardModifiers keyModifiers, bool release);
private:
JogdialControllerSettings m_settings;
QList<JogdialControllerSettings::AvailableChannel> m_availableChannels;
DeviceAPI *m_selectedDevice;
ChannelAPI *m_selectedChannel;
int m_selectedIndex;
bool m_deviceElseChannelControl;
int m_multiplier;
QTimer m_repeatTimer;
static const int m_repeatms = 100;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void start();
void stop();
void applySettings(const JogdialControllerSettings& settings, bool force = false);
void updateChannels();
void channelUp();
void channelDown();
void webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const JogdialControllerSettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleChannelMessageQueue(MessageQueue *messageQueues);
void handleRepeat();
};
#endif // INCLUDE_FEATURE_DEMODANALYZER_H_

Wyświetl plik

@ -0,0 +1,362 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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 <QMessageBox>
#include <QMouseEvent>
#include "feature/featureuiset.h"
#include "gui/basicfeaturesettingsdialog.h"
#include "device/deviceset.h"
#include "util/db.h"
#include "maincore.h"
#include "ui_jogdialcontrollergui.h"
#include "jogdialcontroller.h"
#include "jogdialcontrollergui.h"
JogdialControllerGUI* JogdialControllerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
{
JogdialControllerGUI* gui = new JogdialControllerGUI(pluginAPI, featureUISet, feature);
return gui;
}
void JogdialControllerGUI::destroy()
{
delete this;
}
void JogdialControllerGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray JogdialControllerGUI::serialize() const
{
return m_settings.serialize();
}
bool JogdialControllerGUI::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
displaySettings();
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool JogdialControllerGUI::handleMessage(const Message& message)
{
if (JogdialController::MsgConfigureJogdialController::match(message))
{
qDebug("JogdialControllerGUI::handleMessage: JogdialController::MsgConfigureJogdialController");
const JogdialController::MsgConfigureJogdialController& cfg = (JogdialController::MsgConfigureJogdialController&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (JogdialController::MsgReportChannels::match(message))
{
qDebug("JogdialControllerGUI::handleMessage: JogdialController::MsgReportChannels");
JogdialController::MsgReportChannels& report = (JogdialController::MsgReportChannels&) message;
m_availableChannels = report.getAvailableChannels();
updateChannelList();
return true;
}
else if (JogdialController::MsgReportControl::match(message))
{
qDebug("JogdialControllerGUI::handleMessage: JogdialController::MsgReportControl");
JogdialController::MsgReportControl& report = (JogdialController::MsgReportControl&) message;
ui->controlLabel->setText(report.getDeviceElseChannel() ? "D" : "C");
return true;
}
else if (JogdialController::MsgSelectChannel::match(message))
{
qDebug("JogdialControllerGUI::handleMessage: JogdialController::MsgSelectChannel");
JogdialController::MsgSelectChannel& report = (JogdialController::MsgSelectChannel&) message;
int index = report.getIndex();
if ((index >= 0) && (index < m_availableChannels.size()))
{
ui->channels->blockSignals(true);
ui->channels->setCurrentIndex(index);
ui->channels->blockSignals(false);
}
return true;
}
return false;
}
void JogdialControllerGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()))
{
if (handleMessage(*message)) {
delete message;
}
}
}
void JogdialControllerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
(void) rollDown;
m_settings.m_rollupState = saveState();
applySettings();
}
JogdialControllerGUI::JogdialControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
FeatureGUI(parent),
ui(new Ui::JogdialControllerGUI),
m_pluginAPI(pluginAPI),
m_featureUISet(featureUISet),
m_doApplySettings(true),
m_lastFeatureState(0),
m_selectedChannel(nullptr)
{
ui->setupUi(this);
m_helpURL = "plugins/feature/jogdialcontroller/readme.md";
setAttribute(Qt::WA_DeleteOnClose, true);
setChannelWidget(false);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
m_jogdialController = reinterpret_cast<JogdialController*>(feature);
m_jogdialController->setMessageQueueToGUI(&m_inputMessageQueue);
m_featureUISet->addRollupWidget(this);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(1000);
connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
this->installEventFilter(&m_commandKeyReceiver);
displaySettings();
applySettings(true);
}
JogdialControllerGUI::~JogdialControllerGUI()
{
delete ui;
}
void JogdialControllerGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void JogdialControllerGUI::displaySettings()
{
setTitleColor(m_settings.m_rgbColor);
setWindowTitle(m_settings.m_title);
blockApplySettings(true);
restoreState(m_settings.m_rollupState);
blockApplySettings(false);
}
void JogdialControllerGUI::updateChannelList()
{
ui->channels->blockSignals(true);
ui->channels->clear();
QList<JogdialControllerSettings::AvailableChannel>::const_iterator it = m_availableChannels.begin();
int selectedItem = -1;
for (int i = 0; it != m_availableChannels.end(); ++it, i++)
{
ui->channels->addItem(tr("%1%2:%3 %4")
.arg(it->m_tx ? "T" : "R")
.arg(it->m_deviceSetIndex)
.arg(it->m_channelIndex)
.arg(it->m_channelId)
);
if (it->m_channelAPI == m_selectedChannel) {
selectedItem = i;
}
}
int currentSelectedChannelIndex = ui->channels->currentIndex();
ui->channels->blockSignals(false);
if (m_availableChannels.size() > 0)
{
if (selectedItem >= 0) {
ui->channels->setCurrentIndex(selectedItem);
} else {
ui->channels->setCurrentIndex(0);
}
}
if (currentSelectedChannelIndex == ui->channels->currentIndex()) {
on_channels_currentIndexChanged(ui->channels->currentIndex()); // force sending
}
}
void JogdialControllerGUI::leaveEvent(QEvent*)
{
}
void JogdialControllerGUI::enterEvent(QEvent*)
{
}
void JogdialControllerGUI::onMenuDialogCalled(const QPoint &p)
{
if (m_contextMenuType == ContextMenuChannelSettings)
{
BasicFeatureSettingsDialog dialog(this);
dialog.setTitle(m_settings.m_title);
dialog.setColor(m_settings.m_rgbColor);
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex);
dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex);
dialog.move(p);
dialog.exec();
m_settings.m_rgbColor = dialog.getColor().rgb();
m_settings.m_title = dialog.getTitle();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex();
m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex();
setWindowTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
applySettings();
}
resetContextMenuType();
}
void JogdialControllerGUI::on_startStop_toggled(bool checked)
{
if (checked)
{
setFocus();
setFocusPolicy(Qt::StrongFocus);
connect(&m_commandKeyReceiver, SIGNAL(capturedKey(Qt::Key, Qt::KeyboardModifiers, bool)),
m_jogdialController, SLOT(commandKeyPressed(Qt::Key, Qt::KeyboardModifiers, bool)));
}
else
{
disconnect(&m_commandKeyReceiver, SIGNAL(capturedKey(Qt::Key, Qt::KeyboardModifiers, bool)),
m_jogdialController, SLOT(commandKeyPressed(Qt::Key, Qt::KeyboardModifiers, bool)));
setFocusPolicy(Qt::NoFocus);
clearFocus();
}
JogdialController::MsgStartStop *message = JogdialController::MsgStartStop::create(checked);
m_jogdialController->getInputMessageQueue()->push(message);
}
void JogdialControllerGUI::on_devicesRefresh_clicked()
{
JogdialController::MsgRefreshChannels *msg = JogdialController::MsgRefreshChannels::create();
m_jogdialController->getInputMessageQueue()->push(msg);
}
void JogdialControllerGUI::on_channels_currentIndexChanged(int index)
{
if ((index >= 0) && (index < m_availableChannels.size()))
{
m_selectedChannel = m_availableChannels[index].m_channelAPI;
JogdialController::MsgSelectChannel *msg = JogdialController::MsgSelectChannel::create(index);
m_jogdialController->getInputMessageQueue()->push(msg);
}
}
void JogdialControllerGUI::tick()
{
}
void JogdialControllerGUI::updateStatus()
{
int state = m_jogdialController->getState();
if (m_lastFeatureState != state)
{
switch (state)
{
case Feature::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case Feature::StIdle:
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case Feature::StRunning:
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case Feature::StError:
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
QMessageBox::information(this, tr("Message"), m_jogdialController->getErrorMessage());
break;
default:
break;
}
m_lastFeatureState = state;
}
}
void JogdialControllerGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
JogdialController::MsgConfigureJogdialController* message = JogdialController::MsgConfigureJogdialController::create( m_settings, force);
m_jogdialController->getInputMessageQueue()->push(message);
}
}
void JogdialControllerGUI::focusInEvent(QFocusEvent*)
{
qDebug("JogdialControllerGUI::focusInEvent");
ui->focusIndicator->setStyleSheet("QLabel { background-color: rgb(85, 232, 85); border-radius: 8px; }"); // green
ui->focusIndicator->setToolTip("Active");
}
void JogdialControllerGUI::focusOutEvent(QFocusEvent*)
{
qDebug("JogdialControllerGUI::focusOutEvent");
ui->focusIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }"); // gray
ui->focusIndicator->setToolTip("Idle");
}

Wyświetl plik

@ -0,0 +1,93 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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_FEATURE_JOGDIALCONTROLLERGUI_H_
#define INCLUDE_FEATURE_JOGDIALCONTROLLERGUI_H_
#include <QTimer>
#include <QList>
#include "feature/featuregui.h"
#include "util/messagequeue.h"
#include "commands/commandkeyreceiver.h"
#include "jogdialcontrollersettings.h"
class PluginAPI;
class FeatureUISet;
class JogdialController;
class Feature;
namespace Ui {
class JogdialControllerGUI;
}
class JogdialControllerGUI : public FeatureGUI {
Q_OBJECT
public:
static JogdialControllerGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature);
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
protected:
void focusInEvent(QFocusEvent* e);
void focusOutEvent(QFocusEvent *e);
private:
Ui::JogdialControllerGUI* ui;
PluginAPI* m_pluginAPI;
FeatureUISet* m_featureUISet;
JogdialControllerSettings m_settings;
bool m_doApplySettings;
JogdialController* m_jogdialController;
MessageQueue m_inputMessageQueue;
QTimer m_statusTimer;
int m_lastFeatureState;
QList<JogdialControllerSettings::AvailableChannel> m_availableChannels;
ChannelAPI *m_selectedChannel;
CommandKeyReceiver m_commandKeyReceiver;
explicit JogdialControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
virtual ~JogdialControllerGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void updateChannelList();
bool handleMessage(const Message& message);
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
private slots:
void onMenuDialogCalled(const QPoint &p);
void onWidgetRolled(QWidget* widget, bool rollDown);
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_devicesRefresh_clicked();
void on_device_currentIndexChanged(int index);
void on_channels_currentIndexChanged(int index);
void updateStatus();
void tick();
};
#endif // INCLUDE_FEATURE_JOGDIALCONTROLLERGUI_H_

Wyświetl plik

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>JogdialControllerGUI</class>
<widget class="RollupWidget" name="JogdialControllerGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>365</width>
<height>105</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>340</width>
<height>100</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Jogdial Controller</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<height>81</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>360</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Settings</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="mainLayout">
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop plugin</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="QLabel" name="focusIndicator">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="toolTip">
<string>Idle</string>
</property>
<property name="styleSheet">
<string notr="true">QLabel { background-color: gray; border-radius: 8px; }</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh indexes of available device sets</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelLabel">
<property name="text">
<string>Chan</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channels">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel to control</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="controlLabel">
<property name="toolTip">
<string>Device (D) or channel (C) control</string>
</property>
<property name="text">
<string>D</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<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>
<layout class="QHBoxLayout" name="targetLayout">
<item>
<spacer name="horizontalSpacer_2">
<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>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.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>

Wyświetl plik

@ -0,0 +1,80 @@
//////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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"
#ifndef SERVER_MODE
#include "jogdialcontrollergui.h"
#endif
#include "jogdialcontroller.h"
#include "jogdialcontrollerplugin.h"
#include "jogdialcontrollerwebapiadapter.h"
const PluginDescriptor JogdialControllerPlugin::m_pluginDescriptor = {
JogdialController::m_featureId,
QStringLiteral("Jogdial Controller"),
QStringLiteral("6.18.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,
QStringLiteral("https://github.com/f4exb/sdrangel")
};
JogdialControllerPlugin::JogdialControllerPlugin(QObject* parent) :
QObject(parent),
m_pluginAPI(nullptr)
{
}
const PluginDescriptor& JogdialControllerPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void JogdialControllerPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
// register RigCtl Server feature
m_pluginAPI->registerFeature(JogdialController::m_featureIdURI, JogdialController::m_featureId, this);
}
#ifdef SERVER_MODE
FeatureGUI* JogdialControllerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
{
(void) featureUISet;
(void) feature;
return nullptr;
}
#else
FeatureGUI* JogdialControllerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
{
return JogdialControllerGUI::create(m_pluginAPI, featureUISet, feature);
}
#endif
Feature* JogdialControllerPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const
{
return new JogdialController(webAPIAdapterInterface);
}
FeatureWebAPIAdapter* JogdialControllerPlugin::createFeatureWebAPIAdapter() const
{
return new JogdialControllerWebAPIAdapter();
}

Wyświetl plik

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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_FEATURE_JOGDIALCONTROLLERPLUGIN_H
#define INCLUDE_FEATURE_JOGDIALCONTROLLERPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class FeatureGUI;
class WebAPIAdapterInterface;
class JogdialControllerPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "sdrangel.feature.jogdialcontroller")
public:
explicit JogdialControllerPlugin(QObject* parent = nullptr);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const;
virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const;
virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const;
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif // INCLUDE_FEATURE_JOGDIALCONTROLLERPLUGIN_H

Wyświetl plik

@ -0,0 +1,132 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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 <QColor>
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "jogdialcontrollersettings.h"
const QStringList JogdialControllerSettings::m_channelTypes = {
QStringLiteral("AISDemod"),
QStringLiteral("AISMod"),
QStringLiteral("AMDemod"),
QStringLiteral("AMMod"),
QStringLiteral("DABDemod"),
QStringLiteral("DSDDemod"),
QStringLiteral("NFMDemod"),
QStringLiteral("NFMMod"),
QStringLiteral("PacketDemod"),
QStringLiteral("PacketMod"),
QStringLiteral("SSBDemod"),
QStringLiteral("SSBMod"),
QStringLiteral("WFMDemod"),
QStringLiteral("WFMMod"),
};
const QStringList JogdialControllerSettings::m_channelURIs = {
QStringLiteral("sdrangel.channel.aisdemod"),
QStringLiteral("sdrangel.channel.modais"),
QStringLiteral("sdrangel.channel.amdemod"),
QStringLiteral("sdrangel.channeltx.modam"),
QStringLiteral("sdrangel.channel.dabdemod"),
QStringLiteral("sdrangel.channel.dsddemod"),
QStringLiteral("sdrangel.channel.nfmdemod"),
QStringLiteral("sdrangel.channeltx.modnfm"),
QStringLiteral("sdrangel.channel.packetdemod"),
QStringLiteral("sdrangel.channeltx.modpacket"),
QStringLiteral("sdrangel.channel.ssbdemod"),
QStringLiteral("sdrangel.channeltx.modssb"),
QStringLiteral("sdrangel.channel.wfmdemod"),
QStringLiteral("sdrangel.channeltx.modwfm"),
};
JogdialControllerSettings::JogdialControllerSettings()
{
resetToDefaults();
}
void JogdialControllerSettings::resetToDefaults()
{
m_title = "Jogdial Controller";
m_rgbColor = QColor(3, 198, 252).rgb();
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIFeatureSetIndex = 0;
m_reverseAPIFeatureIndex = 0;
}
QByteArray JogdialControllerSettings::serialize() const
{
SimpleSerializer s(1);
s.writeString(5, m_title);
s.writeU32(6, m_rgbColor);
s.writeBool(7, m_useReverseAPI);
s.writeString(8, m_reverseAPIAddress);
s.writeU32(9, m_reverseAPIPort);
s.writeU32(10, m_reverseAPIFeatureSetIndex);
s.writeU32(11, m_reverseAPIFeatureIndex);
s.writeBlob(12, m_rollupState);
return s.final();
}
bool JogdialControllerSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
QByteArray bytetmp;
uint32_t utmp;
QString strtmp;
d.readString(5, &m_title, "Jogdial Controller");
d.readU32(6, &m_rgbColor, QColor(3, 198, 252).rgb());
d.readBool(7, &m_useReverseAPI, false);
d.readString(8, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(9, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(10, &utmp, 0);
m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp;
d.readU32(11, &utmp, 0);
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
d.readBlob(12, &m_rollupState);
return true;
}
else
{
resetToDefaults();
return false;
}
}

Wyświetl plik

@ -0,0 +1,65 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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_FEATURE_JOGDIALCONTROLLERSETTINGS_H_
#define INCLUDE_FEATURE_JOGDIALCONTROLLERSETTINGS_H_
#include <QByteArray>
#include <QString>
#include "util/message.h"
class Serializable;
class ChannelAPI;
class DeviceAPI;
struct JogdialControllerSettings
{
struct AvailableChannel
{
bool m_tx;
int m_deviceSetIndex;
int m_channelIndex;
DeviceAPI *m_deviceAPI;
ChannelAPI *m_channelAPI;
QString m_deviceId;
QString m_channelId;
AvailableChannel() = default;
AvailableChannel(const AvailableChannel&) = default;
AvailableChannel& operator=(const AvailableChannel&) = default;
};
QString m_title;
quint32 m_rgbColor;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIFeatureSetIndex;
uint16_t m_reverseAPIFeatureIndex;
QByteArray m_rollupState;
JogdialControllerSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
static const QStringList m_channelTypes;
static const QStringList m_channelURIs;
};
#endif // INCLUDE_FEATURE_JOGDIALCONTROLLERSETTINGS_H_

Wyświetl plik

@ -0,0 +1,51 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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 "SWGFeatureSettings.h"
#include "jogdialcontroller.h"
#include "jogdialcontrollerwebapiadapter.h"
JogdialControllerWebAPIAdapter::JogdialControllerWebAPIAdapter()
{}
JogdialControllerWebAPIAdapter::~JogdialControllerWebAPIAdapter()
{}
int JogdialControllerWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setDemodAnalyzerSettings(new SWGSDRangel::SWGDemodAnalyzerSettings());
response.getDemodAnalyzerSettings()->init();
JogdialController::webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int JogdialControllerWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) force; // no action
(void) errorMessage;
JogdialController::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
return 200;
}

Wyświetl plik

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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_JOGDIALCONTROLLER_WEBAPIADAPTER_H
#define INCLUDE_JOGDIALCONTROLLER_WEBAPIADAPTER_H
#include "feature/featurewebapiadapter.h"
#include "jogdialcontrollersettings.h"
/**
* Standalone API adapter only for the settings
*/
class JogdialControllerWebAPIAdapter : public FeatureWebAPIAdapter {
public:
JogdialControllerWebAPIAdapter();
virtual ~JogdialControllerWebAPIAdapter();
virtual QByteArray serialize() const { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
private:
JogdialControllerSettings m_settings;
};
#endif // INCLUDE_DEMODANALYZER_WEBAPIADAPTER_H

Wyświetl plik

@ -0,0 +1,297 @@
<h1>Jogdial Controller Feature Plugin</h1>
<h2>Introduction</h2>
This plugin aims at supporting frequency control via a "jog dial". A jog dial, jog wheel, shuttle dial, or shuttle wheel is a type of knob, ring, wheel, or dial which allows the user to shuttle or jog through audio or video media.
It is designed to support the Contour ShuttleXpress and ShuttlePro products but as it is keyboard keys based any device capable of reproducing the same key sequences (including a standard keyboard - see next) can interact with this plugin.
In the last section you will find details about the key sequences and placement of supported knobs on the ShuttleXpress and ShuttlePro.
Note that it is based on Qt keyboard events. These events are supported only for GUI applications therefore this plugin is not built in the server variant.
<h2>Interface</h2>
![Jogdial controller GUI](../../../doc/img/JogdialController_plugin.png)
<h3>1: Start/Stop</h3>
Use this toggle to activate or deactivate the plugin. Note that for the control to be effective the plugin should also have the focus. You can check the focus state with the focus indicator (2)
<h3>2: Focus indicator</h3>
This indicator turns green if the plugin has focus. To set the focus on the plugin just click anywhere on it. The controls are effective only if the plugin has focus.
<h3>3: Refresh channels list</h3>
Use this button to refresh the list of available channels. It will scan through all the device sets presents in the instance to list their channels in the combo box next (4).
Note that on first start the list in (4) is empty therefore you must press this button right after the plugin is started with (1)
<h3>4: Select channel</h3>
Use this combo box to select which channel to control. The list item is formatted this way:
- R ot T for a source (Rx) or sink (Tx) device set
- The sequence number of the device set
- The sequence number of the channel after the semicolon separator
- The type of channel
The frequency of the device of the device set the channel belongs to can also be controlled when device control is selected. The type of control is displayed in (5)
To select the type of control:
- Press K5 on the Contour device or ¨D" (shift+D) on the keyboard for device control
- Press K9 on the Contour device or ¨C" (shift+C) on the keyboard for channel control
<h3>5: Control type indicator</h3>
It displays "D" when in device control or "C" when in channel control mode.
<h2>Contour products and keyboard control</h2>
<h3>Contour devices</h3>
The Controur devices generally have a central "jog" wheel inside a spring loaded ring called the "shuttle" wheel plus a series of buttons.
<b>ShuttleXpress layout</b>
![ShuttleXpress layout](../../../doc/img/ShuttleXpressLayout.png)
<b>ShuttlePRO layout</b>
![ShuttlePRO layout](../../../doc/img/ShuttlePROLayout.png)
The **jog wheel** is used to go up and down in discrete frequency units. You can use the Ctl and Shift keys on the keyboard simultaneously to select the frequency step:
- No key: &plusmn; 1 Hz for channels &plusmn; 1 kHz for devices
- Ctl key: &plusmn; 10 Hz for channels &plusmn; 10 kHz for devices
- Shift key: &plusmn; 100 Hz for channels &plusmn; 100 kHz for devices
- Ctl+Shift key: &plusmn; 1 kHz for channels &plusmn; 1 MHz for devices
The **shuttle wheel** has a central rest position and 7 positions on the left and 7 on the right. The left positions are used to go down in frequency and the right positions to go up. The frequency increments or decrements are sent every 100 ms as long as the shuttle position is maintained. It stops at rest (central) position. The further you go from the center the larger the frequency increment or decrement at each step. The amount is multiplied by 10 from one position to the next as you move away from the center. Thus to summarize:
- Center: rest position stops moving
- &plusmn; 1 step: moves &plusmn; 1 unit (1 Hz for channels, 1 kHz for devices)
- &plusmn; 2 steps: moves &plusmn; 10 units
- &plusmn; 3 steps: moves &plusmn; 100 units
- &plusmn; 4 steps: moves &plusmn; 1000 units (1 kHz for channels, 1 MHz for devices)
- &plusmn; 5 steps: moves &plusmn; 10000 units
- &plusmn; 6 steps: moves &plusmn; 100000 units
- &plusmn; 7 steps: moves &plusmn; 1000000 units (1 MHz for channels, 1 GHz for devices)
The **keys** are mapped as follows:
- K5: Select device control
- K6: Move down through the list of available channels
- K7: Center the channel (set its frequency to 0) - useful when you loose the channel out of the baseband window
- K8: Move up through the list of available channels
- K9: Select channel control
<h3>Mapping to keyboard and keyboard control</h3>
The contour devices proceed by mapping their events to keyboard events and this makes them very adaptable. The Jogdial Controller feature is keyboard event based so you may as well use your keyboard for control. In that case for better visual mapping it is recommended to use a US or US International keyboard.
Contour provides software to perform the mapping on Windows. So when running on Windows please refer to Contour documentation to implement the keyboard sequence mapping that is described next.
When running on Linux ou may use [ShuttlePRO](https://github.com/nanosyzygy/ShuttlePRO) for keyboard mapping. It will work also for the ShuttleXpress with minor changes. You will have to identify the path of the Shuttle device and run the program against it in a terminal. See the last section for details.
<h4>Keyboard mapping</h4>
The shuttle devices controls are mapped according to the following table. K5 to K9 represent the shuttle keys. S-7 to S7 represent the shuttle (outer ring) positions S0 being the rest middle position. JL is a jog step to the left and JR a jog step to the right:
<table>
<tr>
<th>Shuttle</th>
<th>Keyboard</th>
<th>Key sequence (US)</th>
<th>Action</th>
</tr>
<tr>
<td>K5</td>
<td>D</td>
<td>Shift+D</td>
<td>Device control</td>
<tr>
<tr>
<td>K6</td>
<td>&larr;</td>
<td>&larr;</td>
<td>Previous channel</td>
<tr>
<tr>
<td>K7</td>
<td>Home</td>
<td>Home</td>
<td>Center channel</td>
<tr>
<tr>
<td>K8</td>
<td>&rarr;</td>
<td>&rarr;</td>
<td>Next channel</td>
<tr>
<tr>
<td>K9</td>
<td>C</td>
<td>Shift+C</td>
<td>Channel control</td>
<tr>
<tr>
<td>S-7</td>
<td>&amp;</td>
<td>Shift+7</td>
<td>Continuous -1 MHz / -1 GHz move</td>
<tr>
<tr>
<td>S-6</td>
<td>&Hat;</td>
<td>Shift+6</td>
<td>Continuous -100 kHz / -100 MHz move</td>
<tr>
<tr>
<td>S-5</td>
<td>&percnt;</td>
<td>Shift+5</td>
<td>Continuous -10 kHz / -10 MHz move</td>
<tr>
<tr>
<td>S-4</td>
<td>&dollar;</td>
<td>Shift+4</td>
<td>Continuous -1 kHz / -1 MHz move</td>
<tr>
<tr>
<td>S-3</td>
<td>#</td>
<td>Shift+3</td>
<td>Continuous -100 Hz / -100 kHz move</td>
<tr>
<tr>
<td>S-2</td>
<td>&commat;</td>
<td>Shift+2</td>
<td>Continuous -10 Hz / -10 kHz move</td>
<tr>
<tr>
<td>S-1</td>
<td>&excl;</td>
<td>Shift+1</td>
<td>Continuous -1 Hz / -1 kHz move</td>
<tr>
<tr>
<td>S0</td>
<td>0</td>
<td>0</td>
<td>Stop continuous move</td>
<tr>
<tr>
<td>S1</td>
<td>1</td>
<td>1</td>
<td>Continuous +1 Hz / +1 kHz move</td>
<tr>
<tr>
<td>S2</td>
<td>2</td>
<td>2</td>
<td>Continuous +10 Hz / +10 kHz move</td>
<tr>
<tr>
<td>S3</td>
<td>3</td>
<td>3</td>
<td>Continuous +100 Hz / +100 kHz move</td>
<tr>
<tr>
<td>S4</td>
<td>4</td>
<td>4</td>
<td>Continuous +1 kHz / +1 MHz move</td>
<tr>
<tr>
<td>S5</td>
<td>5</td>
<td>5</td>
<td>Continuous +10 kHz / +10 MHz move</td>
<tr>
<tr>
<td>S6</td>
<td>6</td>
<td>6</td>
<td>Continuous +100 kHz / +100 MHz move</td>
<tr>
<tr>
<td>S7</td>
<td>7</td>
<td>7</td>
<td>Continuous +1 MHz / +1 GHz move</td>
<tr>
<tr>
<td>JL</td>
<td>&darr;</td>
<td>&darr;</td>
<td>Single -1/-10/-100/-1000 (Hz/kHz) move</td>
<tr>
<tr>
<td>JR</td>
<td>&uarr;</td>
<td>&uarr;</td>
<td>Single +1/+10/+100/+1000 (Hz/kHz) move</td>
<tr>
</table>
<h4>US keyboard mapping</h4>
![US keyboard layout](../../../doc/img/USKeyboardLayout.png)
<h3>Running the Contour devices in Linux</h3>
As briefly introduced earlier you may use [ShuttlePRO](https://github.com/nanosyzygy/ShuttlePRO) for keyboard mapping.
The program will normally work as-is for ShuttlePRO. It will also work for ShuttleXpress with a few adaptations detailed next.
Firstly you need to add the proper udev rules that are slightly different. In fact you just need to change the "ATTR" line by:
```
ATTRS{name}=="Contour Design ShuttleXpress" MODE="0644"
```
Secondly the device path is different for ShuttleXPress. You have to look for your device in the path starting with `/dev/input/by-id/usb-Contour_Design_` In most cases this will be: `/dev/input/by-id/usb-Contour_Design_ShuttleXpress-event-if00`
You will then use this path as argument to the `shuttlepro` program:
`shuttlepro /dev/input/by-id/usb-Contour_Design_ShuttleXpress-event-if00`
You may change the argument in the `shuttle` script for convenience:
`exec shuttlepro /dev/input/by-id/usb-Contour_Design_ShuttleXpress-event-if00`
In any case you need to specify the mapping in the `~/.shuttlerc` file by adding a section for SDRangel like this:
```
[SDRangel]
K5 "D"
K6 XK_Left
K7 XK_Home
K8 XK_Right
K9 "C"
S-7 XK_Shift_L/D "7"
S-6 XK_Shift_L/D "6"
S-5 XK_Shift_L/D "5"
S-4 XK_Shift_L/D "4"
S-3 XK_Shift_L/D "3"
S-2 XK_Shift_L/D "2"
S-1 XK_Shift_L/D "1"
S0 "0"
S1 "1"
S2 "2"
S3 "3"
S4 "4"
S5 "5"
S6 "6"
S7 "7"
JL XK_Down
JR XK_Up
```

Some files were not shown because too many files have changed in this diff Show More