Add AvailableChannelOrFeatureHandler for handling lists of channels, features and message pipes to them.

This commit is contained in:
srcejon 2024-02-16 16:31:12 +00:00
parent 607d7db702
commit 483e338614
47 changed files with 1040 additions and 1441 deletions

View File

@ -67,6 +67,7 @@ FreqScanner::FreqScanner(DeviceAPI *deviceAPI) :
m_basebandSink(nullptr),
m_running(false),
m_basebandSampleRate(0),
m_availableChannelHandler({}),
m_scanDeviceSetIndex(0),
m_scanChannelIndex(0),
m_state(IDLE),
@ -95,19 +96,8 @@ FreqScanner::FreqScanner(DeviceAPI *deviceAPI) :
start();
scanAvailableChannels();
QObject::connect(
MainCore::instance(),
&MainCore::channelAdded,
this,
&FreqScanner::handleChannelAdded
);
QObject::connect(
MainCore::instance(),
&MainCore::channelRemoved,
this,
&FreqScanner::handleChannelRemoved
);
QObject::connect(&m_availableChannelHandler, &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged, this, &FreqScanner::channelsChanged);
m_availableChannelHandler.scanAvailableChannelsAndFeatures();
m_timeoutTimer.callOnTimeout(this, &FreqScanner::timeout);
}
@ -708,7 +698,7 @@ void FreqScanner::applySettings(const FreqScannerSettings& settings, const QStri
m_deviceAPI->removeChannelSink(this, m_settings.m_streamIndex);
m_deviceAPI->addChannelSink(this, settings.m_streamIndex);
m_deviceAPI->addChannelSinkAPI(this);
scanAvailableChannels(); // re-scan
//FIXME:scanAvailableChannels(); // re-scan
emit streamIndexChanged(settings.m_streamIndex);
}
}
@ -1116,186 +1106,18 @@ void FreqScanner::handleIndexInDeviceSetChanged(int index)
m_basebandSink->setFifoLabel(fifoLabel);
}
void FreqScanner::scanAvailableChannels()
void FreqScanner::channelsChanged(const QStringList& renameFrom, const QStringList& renameTo)
{
m_availableChannels.clear();
DSPDeviceSourceEngine* deviceSourceEngine = getDeviceAPI()->getDeviceSourceEngine();
if (deviceSourceEngine)
{
for (int chi = 0; chi < getDeviceAPI()->getNbSinkChannels(); chi++) // Rx channels
{
ChannelAPI* channel = getDeviceAPI()->getChanelSinkAPIAt(chi);
if (channel->getIndexInDeviceSet() == getIndexInDeviceSet()) { // Exclude oneself
continue;
}
FreqScannerSettings::AvailableChannel availableChannel =
FreqScannerSettings::AvailableChannel{
channel->getDeviceSetIndex(),
channel->getIndexInDeviceSet(),
-1
};
m_availableChannels[channel] = availableChannel;
QObject::connect(
channel,
&ChannelAPI::streamIndexChanged,
[=](int streamIndex){
this->handleChannelStreamIndexChanged(streamIndex, channel);
}
);
}
}
DSPDeviceMIMOEngine *deviceMIMOEngine = getDeviceAPI()->getDeviceMIMOEngine();
if (deviceMIMOEngine)
{
for (int chi = 0; chi < getDeviceAPI()->getNbSinkChannels(); chi++) // Rx channels
{
ChannelAPI* channel = getDeviceAPI()->getChanelSinkAPIAt(chi);
if (channel->getIndexInDeviceSet() == getIndexInDeviceSet()) { // Exclude oneself
continue;
}
// Single Rx on the same I/Q stream
if ((channel->getNbSinkStreams() == 1)
&& (channel->getNbSourceStreams() == 0)
&& (channel->getStreamIndex() == m_settings.m_streamIndex))
{
FreqScannerSettings::AvailableChannel availableChannel =
FreqScannerSettings::AvailableChannel{
channel->getDeviceSetIndex(),
channel->getIndexInDeviceSet(),
channel->getStreamIndex()
};
m_availableChannels[channel] = availableChannel;
QObject::connect(
channel,
&ChannelAPI::streamIndexChanged,
[=](int streamIndex){
this->handleChannelStreamIndexChanged(streamIndex, channel);
}
);
}
}
}
notifyUpdateChannels();
m_availableChannels = m_availableChannelHandler.getAvailableChannelOrFeatureList();
notifyUpdateChannels(renameFrom, renameTo);
}
void FreqScanner::handleChannelAdded(int deviceSetIndex, ChannelAPI* channel)
{
if (deviceSetIndex != getDeviceSetIndex()) { // Can control channels only in the same device set
return;
}
qDebug("FreqScanner::handleChannelAdded: deviceSetIndex: %d:%d channel: %s (%p)",
deviceSetIndex, channel->getIndexInDeviceSet(), qPrintable(channel->getURI()), channel);
DSPDeviceSourceEngine* deviceSourceEngine = getDeviceAPI()->getDeviceSourceEngine();
if (deviceSourceEngine)
{
FreqScannerSettings::AvailableChannel availableChannel =
FreqScannerSettings::AvailableChannel{ deviceSetIndex, channel->getIndexInDeviceSet(), -1};
m_availableChannels[channel] = availableChannel;
QObject::connect(
channel,
&ChannelAPI::streamIndexChanged,
[=](int streamIndex){
this->handleChannelStreamIndexChanged(streamIndex, channel);
}
);
}
DSPDeviceMIMOEngine *deviceMIMOEngine = getDeviceAPI()->getDeviceMIMOEngine();
if (deviceMIMOEngine
&& (channel->getNbSinkStreams() == 1)
&& (channel->getNbSourceStreams() == 0)
&& (channel->getStreamIndex() == m_settings.m_streamIndex))
{
FreqScannerSettings::AvailableChannel availableChannel =
FreqScannerSettings::AvailableChannel{
deviceSetIndex,
channel->getIndexInDeviceSet(),
channel->getStreamIndex()
};
m_availableChannels[channel] = availableChannel;
QObject::connect(
channel,
&ChannelAPI::streamIndexChanged,
[=](int streamIndex){
this->handleChannelStreamIndexChanged(streamIndex, channel);
}
);
}
notifyUpdateChannels();
}
void FreqScanner::handleChannelRemoved(int deviceSetIndex, ChannelAPI* channel)
{
if (deviceSetIndex != getDeviceSetIndex()) { // Can control channels only in the same device set
return;
}
qDebug("FreqScanner::handleChannelRemoved: deviceSetIndex: %d:%d channel: %s (%p)",
deviceSetIndex, channel->getIndexInDeviceSet(), qPrintable(channel->getURI()), channel);
DSPDeviceSourceEngine* deviceSourceEngine = getDeviceAPI()->getDeviceSourceEngine();
DSPDeviceMIMOEngine *deviceMIMOEngine = getDeviceAPI()->getDeviceMIMOEngine();
if (deviceSourceEngine || deviceMIMOEngine) {
m_availableChannels.remove(channel);
}
notifyUpdateChannels();
}
void FreqScanner::handleChannelStreamIndexChanged(int streamIndex, ChannelAPI* channel)
{
qDebug("FreqScanner::handleChannelStreamIndexChanged: channel: %s (%p) stream: %d",
qPrintable(channel->getURI()), channel, streamIndex);
if (streamIndex != m_settings.m_streamIndex) // channel has moved to another I/Q stream
{
m_availableChannels.remove(channel);
notifyUpdateChannels();
}
else if (!m_availableChannels.contains(channel)) // if channel has been tracked before put back it in the list
{
FreqScannerSettings::AvailableChannel availableChannel =
FreqScannerSettings::AvailableChannel{
getDeviceSetIndex(),
channel->getIndexInDeviceSet(),
channel->getStreamIndex()
};
m_availableChannels[channel] = availableChannel;
notifyUpdateChannels();
}
}
void FreqScanner::notifyUpdateChannels()
void FreqScanner::notifyUpdateChannels(const QStringList& renameFrom, const QStringList& renameTo)
{
if (getMessageQueueToGUI())
{
MsgReportChannels* msgToGUI = MsgReportChannels::create();
QList<FreqScannerSettings::AvailableChannel>& msgChannels = msgToGUI->getChannels();
QHash<ChannelAPI*, FreqScannerSettings::AvailableChannel>::iterator it = m_availableChannels.begin();
for (; it != m_availableChannels.end(); ++it)
{
FreqScannerSettings::AvailableChannel msgChannel =
FreqScannerSettings::AvailableChannel{
it->m_deviceSetIndex,
it->m_channelIndex,
it->m_streamIndex
};
msgChannels.push_back(msgChannel);
}
MsgReportChannels* msgToGUI = MsgReportChannels::create(renameFrom, renameTo);
msgToGUI->getChannels() = m_availableChannels;
getMessageQueueToGUI()->push(msgToGUI);
}
}

View File

@ -27,6 +27,7 @@
#include "dsp/basebandsamplesink.h"
#include "channel/channelapi.h"
#include "util/message.h"
#include "availablechannelorfeaturehandler.h"
#include "freqscannerbaseband.h"
#include "freqscannersettings.h"
@ -71,17 +72,23 @@ public:
public:
QList<FreqScannerSettings::AvailableChannel>& getChannels() { return m_channels; }
AvailableChannelOrFeatureList& getChannels() { return m_channels; }
const QStringList& getRenameFrom() const { return m_renameFrom; }
const QStringList& getRenameTo() const { return m_renameTo; }
static MsgReportChannels* create() {
return new MsgReportChannels();
static MsgReportChannels* create(const QStringList& renameFrom, const QStringList& renameTo) {
return new MsgReportChannels(renameFrom, renameTo);
}
private:
QList<FreqScannerSettings::AvailableChannel> m_channels;
AvailableChannelOrFeatureList m_channels;
QStringList m_renameFrom;
QStringList m_renameTo;
MsgReportChannels() :
Message()
MsgReportChannels(const QStringList& renameFrom, const QStringList& renameTo) :
Message(),
m_renameFrom(renameFrom),
m_renameTo(renameTo)
{}
};
@ -369,7 +376,8 @@ private:
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
QHash<ChannelAPI*, FreqScannerSettings::AvailableChannel> m_availableChannels;
AvailableChannelOrFeatureList m_availableChannels;
AvailableChannelOrFeatureHandler m_availableChannelHandler;
unsigned int m_scanDeviceSetIndex;
unsigned int m_scanChannelIndex;
@ -402,8 +410,8 @@ private:
);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void scanAvailableChannels();
void notifyUpdateChannels();
//void scanAvailableChannels();
void notifyUpdateChannels(const QStringList& renameFrom, const QStringList& renameTo);
void startScan();
void stopScan();
void initScan();
@ -416,9 +424,7 @@ private:
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleIndexInDeviceSetChanged(int index);
void handleChannelAdded(int deviceSetIndex, ChannelAPI* channel);
void handleChannelRemoved(int deviceSetIndex, ChannelAPI* channel);
void handleChannelStreamIndexChanged(int streamIndex, ChannelAPI* channel);
void channelsChanged(const QStringList& renameFrom, const QStringList& renameTo);
void timeout();
};

View File

@ -118,8 +118,7 @@ bool FreqScannerGUI::handleMessage(const Message& message)
else if (FreqScanner::MsgReportChannels::match(message))
{
FreqScanner::MsgReportChannels& report = (FreqScanner::MsgReportChannels&)message;
m_availableChannels = report.getChannels();
updateChannelsList(m_availableChannels);
updateChannelsList(report.getChannels(), report.getRenameFrom(), report.getRenameTo());
return true;
}
else if (FreqScanner::MsgStatus::match(message))
@ -212,7 +211,7 @@ bool FreqScannerGUI::handleMessage(const Message& message)
return false;
}
void FreqScannerGUI::updateChannelsCombo(QComboBox *combo, const QList<FreqScannerSettings::AvailableChannel>& channels, const QString& channel, bool empty)
void FreqScannerGUI::updateChannelsCombo(QComboBox *combo, const AvailableChannelOrFeatureList& channels, const QString& channel, bool empty)
{
combo->blockSignals(true);
combo->clear();
@ -223,17 +222,8 @@ void FreqScannerGUI::updateChannelsCombo(QComboBox *combo, const QList<FreqScann
for (const auto& channel : channels)
{
// Add channels in this device set, other than ourself (Don't use ChannelGUI::getDeviceSetIndex()/getIndex() as not valid when this is first called)
if ((channel.m_deviceSetIndex == m_freqScanner->getDeviceSetIndex()) && (channel.m_channelIndex != m_freqScanner->getIndexInDeviceSet()))
{
QString name;
if (channel.m_streamIndex < 0) { // Rx
name = QString("R%1:%2").arg(channel.m_deviceSetIndex).arg(channel.m_channelIndex);
} else { // MIMO
name = QString("M%1:%2.%3").arg(channel.m_deviceSetIndex).arg(channel.m_channelIndex).arg(channel.m_streamIndex);
}
combo->addItem(name);
if ((channel.m_superIndex == m_freqScanner->getDeviceSetIndex()) && (channel.m_index != m_freqScanner->getIndexInDeviceSet())) {
combo->addItem(channel.getId());
}
}
@ -250,8 +240,29 @@ void FreqScannerGUI::updateChannelsCombo(QComboBox *combo, const QList<FreqScann
combo->blockSignals(false);
}
void FreqScannerGUI::updateChannelsList(const QList<FreqScannerSettings::AvailableChannel>& channels)
void FreqScannerGUI::updateChannelsList(const AvailableChannelOrFeatureList& channels, const QStringList& renameFrom, const QStringList& renameTo)
{
m_availableChannels = channels;
// Update channel setting if it has been renamed
if (renameFrom.contains(m_settings.m_channel))
{
m_settings.m_channel = renameTo[renameFrom.indexOf(m_settings.m_channel)];
applySetting("channel");
}
bool rename = false;
for (auto& setting : m_settings.m_frequencySettings)
{
if (renameFrom.contains(setting.m_channel))
{
setting.m_channel = renameTo[renameFrom.indexOf(setting.m_channel)];
rename = true;
}
}
if (rename) {
applySetting("frequencySettings");
}
updateChannelsCombo(ui->channels, channels, m_settings.m_channel, false);
for (int row = 0; row < ui->table->rowCount(); row++)
@ -515,10 +526,12 @@ void FreqScannerGUI::applySetting(const QString& settingsKey)
void FreqScannerGUI::applySettings(const QStringList& settingsKeys, bool force)
{
m_settingsKeys.append(settingsKeys);
if (m_doApplySettings)
{
FreqScanner::MsgConfigureFreqScanner* message = FreqScanner::MsgConfigureFreqScanner::create(m_settings, settingsKeys, force);
FreqScanner::MsgConfigureFreqScanner* message = FreqScanner::MsgConfigureFreqScanner::create(m_settings, m_settingsKeys, force);
m_freqScanner->getInputMessageQueue()->push(message);
m_settingsKeys.clear();
}
}

View File

@ -73,6 +73,7 @@ private:
ChannelMarker m_channelMarker;
RollupState m_rollupState;
FreqScannerSettings m_settings;
QList<QString> m_settingsKeys;
qint64 m_deviceCenterFrequency;
bool m_doApplySettings;
@ -82,7 +83,7 @@ private:
QMenu *m_menu;
QList<FreqScannerSettings::AvailableChannel> m_availableChannels;
AvailableChannelOrFeatureList m_availableChannels;
explicit FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
virtual ~FreqScannerGUI();
@ -98,8 +99,8 @@ private:
void addRow(const FreqScannerSettings::FrequencySettings& frequencySettings);
void updateAnnotation(int row);
void updateAnnotations();
void updateChannelsCombo(QComboBox *combo, const QList<FreqScannerSettings::AvailableChannel>& channels, const QString& channel, bool empty);
void updateChannelsList(const QList<FreqScannerSettings::AvailableChannel>& channels);
void updateChannelsCombo(QComboBox *combo, const AvailableChannelOrFeatureList& channels, const QString& channel, bool empty);
void updateChannelsList(const AvailableChannelOrFeatureList& channels, const QStringList& renameFrom, const QStringList& renameTo);
void setAllEnabled(bool enable);
void leaveEvent(QEvent*);

View File

@ -31,17 +31,6 @@ class ChannelAPI;
struct FreqScannerSettings
{
struct AvailableChannel
{
int m_deviceSetIndex;
int m_channelIndex;
int m_streamIndex;
AvailableChannel() = default;
AvailableChannel(const AvailableChannel&) = default;
AvailableChannel& operator=(const AvailableChannel&) = default;
};
struct FrequencySettings {
qint64 m_frequency;
bool m_enabled;

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
// Copyright (C) 2021 Jon Beniston, M7RCE //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE //
// //
// 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 //
@ -67,10 +67,12 @@ const char * const RadioAstronomy::m_channelIdURI = "sdrangel.channel.radioastro
const char * const RadioAstronomy::m_channelId = "RadioAstronomy";
RadioAstronomy::RadioAstronomy(DeviceAPI *deviceAPI) :
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
m_deviceAPI(deviceAPI),
m_basebandSampleRate(0),
m_sweeping(false)
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
m_deviceAPI(deviceAPI),
m_basebandSampleRate(0),
m_sweeping(false),
m_availableFeatureHandler({"sdrangel.feature.startracker"}, QStringList{"startracker.target"}),
m_availableRotatorHandler({"sdrangel.feature.gs232controller"})
{
qDebug("RadioAstronomy::RadioAstronomy");
setObjectName(m_channelId);
@ -105,17 +107,26 @@ RadioAstronomy::RadioAstronomy(DeviceAPI *deviceAPI) :
&RadioAstronomy::handleIndexInDeviceSetChanged
);
QObject::connect(
MainCore::instance(),
&MainCore::featureAdded,
&m_availableFeatureHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&RadioAstronomy::handleFeatureAdded
&RadioAstronomy::handleFeatureMessageQueue
);
QObject::connect(
MainCore::instance(),
&MainCore::featureRemoved,
&m_availableFeatureHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&RadioAstronomy::handleFeatureRemoved
&RadioAstronomy::featuresChanged
);
m_availableFeatureHandler.scanAvailableChannelsAndFeatures();
QObject::connect(
&m_availableRotatorHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&RadioAstronomy::rotatorsChanged
);
m_availableRotatorHandler.scanAvailableChannelsAndFeatures();
m_sweepTimer.setSingleShot(true);
}
@ -123,17 +134,20 @@ RadioAstronomy::RadioAstronomy(DeviceAPI *deviceAPI) :
RadioAstronomy::~RadioAstronomy()
{
qDebug("RadioAstronomy::~RadioAstronomy");
QObject::disconnect(
MainCore::instance(),
&MainCore::featureRemoved,
QObject::disconnect(&m_availableFeatureHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&RadioAstronomy::handleFeatureRemoved
&RadioAstronomy::handleFeatureMessageQueue
);
QObject::disconnect(
MainCore::instance(),
&MainCore::featureAdded,
QObject::disconnect(&m_availableFeatureHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&RadioAstronomy::handleFeatureAdded
&RadioAstronomy::featuresChanged
);
QObject::disconnect(&m_availableRotatorHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&RadioAstronomy::rotatorsChanged
);
QObject::disconnect(
m_networkManager,
@ -194,8 +208,6 @@ void RadioAstronomy::start()
m_basebandSink->getInputMessageQueue()->push(new DSPSignalNotification(m_basebandSampleRate, m_centerFrequency));
m_basebandSink->getInputMessageQueue()->push(RadioAstronomyBaseband::MsgConfigureRadioAstronomyBaseband::create(m_settings, true));
m_worker->getInputMessageQueue()->push(RadioAstronomyWorker::MsgConfigureRadioAstronomyWorker::create(m_settings, true));
scanAvailableFeatures();
}
void RadioAstronomy::stop()
@ -330,7 +342,8 @@ bool RadioAstronomy::handleMessage(const Message& cmd)
}
else if (MsgScanAvailableFeatures::match(cmd))
{
scanAvailableFeatures();
notifyUpdateFeatures({}, {});
notifyUpdateRotators({}, {});
return true;
}
else
@ -753,22 +766,14 @@ void RadioAstronomy::applySettings(const RadioAstronomySettings& settings, bool
{
if (!settings.m_starTracker.isEmpty())
{
Feature *feature = nullptr;
for (const auto& fval : m_availableFeatures)
int index = m_availableFeatures.indexOfLongId(settings.m_starTracker);
if (index >= 0)
{
QString starTrackerText = tr("F%1:%2 %3").arg(fval.m_featureSetIndex).arg(fval.m_featureIndex).arg(fval.m_type);
if (settings.m_starTracker == starTrackerText)
{
feature = m_availableFeatures.key(fval);
break;
}
m_selectedPipe = m_availableFeatures[index].m_object;
}
if (feature) {
m_selectedPipe = feature;
} else {
else
{
m_selectedPipe = nullptr;
qDebug() << "RadioAstronomy::applySettings: No plugin corresponding to target " << settings.m_starTracker;
}
}
@ -1246,145 +1251,39 @@ void RadioAstronomy::handleIndexInDeviceSetChanged(int index)
m_basebandSink->setFifoLabel(fifoLabel);
}
void RadioAstronomy::scanAvailableFeatures()
void RadioAstronomy::featuresChanged(const QStringList& renameFrom, const QStringList& renameTo)
{
qDebug("RadioAstronomy::scanAvailableFeatures");
MainCore *mainCore = MainCore::instance();
MessagePipes& messagePipes = mainCore->getMessagePipes();
std::vector<FeatureSet*>& featureSets = mainCore->getFeatureeSets();
m_availableFeatures.clear();
m_rotators.clear();
for (const auto& featureSet : featureSets)
{
for (int fei = 0; fei < featureSet->getNumberOfFeatures(); fei++)
{
Feature *feature = featureSet->getFeatureAt(fei);
if (RadioAstronomySettings::m_pipeURIs.contains(feature->getURI()))
{
if (!m_availableFeatures.contains(feature))
{
qDebug("RadioAstronomy::scanAvailableFeatures: register %d:%d %s (%p)",
featureSet->getIndex(), fei, qPrintable(feature->getURI()), feature);
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(feature, this, "startracker.target");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleFeatureMessageQueue(messageQueue); },
Qt::QueuedConnection
);
connect(pipe, SIGNAL(toBeDeleted(int, QObject*)), this, SLOT(handleMessagePipeToBeDeleted(int, QObject*)));
RadioAstronomySettings::AvailableFeature availableFeature =
RadioAstronomySettings::AvailableFeature{featureSet->getIndex(), fei, feature->getIdentifier()};
m_availableFeatures[feature] = availableFeature;
}
}
else if (feature->getURI() == "sdrangel.feature.gs232controller")
{
RadioAstronomySettings::AvailableFeature rotator =
RadioAstronomySettings::AvailableFeature{featureSet->getIndex(), fei, feature->getIdentifier()};
m_rotators[feature] = rotator;
}
}
}
notifyUpdateFeatures();
notifyUpdateRotators();
m_availableFeatures = m_availableFeatureHandler.getAvailableChannelOrFeatureList();
notifyUpdateFeatures(renameFrom, renameTo);
}
void RadioAstronomy::notifyUpdateFeatures()
void RadioAstronomy::notifyUpdateFeatures(const QStringList& renameFrom, const QStringList& renameTo)
{
if (getMessageQueueToGUI())
{
MsgReportAvailableFeatures *msg = MsgReportAvailableFeatures::create();
msg->getFeatures() = m_availableFeatures.values();
MsgReportAvailableFeatures *msg = MsgReportAvailableFeatures::create(renameFrom, renameTo);
msg->getFeatures() = m_availableFeatures;
getMessageQueueToGUI()->push(msg);
}
}
void RadioAstronomy::notifyUpdateRotators()
void RadioAstronomy::rotatorsChanged(const QStringList& renameFrom, const QStringList& renameTo)
{
m_rotators = m_availableRotatorHandler.getAvailableChannelOrFeatureList();
notifyUpdateRotators(renameFrom, renameTo);
}
void RadioAstronomy::notifyUpdateRotators(const QStringList& renameFrom, const QStringList& renameTo)
{
if (getMessageQueueToGUI())
{
MsgReportAvailableRotators *msg = MsgReportAvailableRotators::create();
msg->getFeatures() = m_rotators.values();
MsgReportAvailableRotators *msg = MsgReportAvailableRotators::create(renameFrom, renameTo);
msg->getFeatures() = m_rotators;
getMessageQueueToGUI()->push(msg);
}
}
void RadioAstronomy::handleFeatureAdded(int featureSetIndex, Feature *feature)
{
qDebug("RadioAstronomy::handleFeatureAdded: featureSetIndex: %d:%d feature: %s (%p)",
featureSetIndex, feature->getIndexInFeatureSet(), qPrintable(feature->getURI()), feature);
FeatureSet *featureSet = MainCore::instance()->getFeatureeSets()[featureSetIndex];
if (RadioAstronomySettings::m_pipeURIs.contains(feature->getURI()))
{
int fei = feature->getIndexInFeatureSet();
if (!m_availableFeatures.contains(feature))
{
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(feature, this, "startracker.target");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleFeatureMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&RadioAstronomy::handleMessagePipeToBeDeleted
);
}
RadioAstronomySettings::AvailableFeature availableFeature =
RadioAstronomySettings::AvailableFeature{featureSet->getIndex(), fei, feature->getIdentifier()};
m_availableFeatures[feature] = availableFeature;
notifyUpdateFeatures();
}
else if (feature->getURI() == "sdrangel.feature.gs232controller")
{
if (!m_rotators.contains(feature))
{
RadioAstronomySettings::AvailableFeature rotator =
RadioAstronomySettings::AvailableFeature{featureSet->getIndex(), feature->getIndexInFeatureSet(), feature->getIdentifier()};
m_rotators[feature] = rotator;
}
notifyUpdateRotators();
}
}
void RadioAstronomy::handleFeatureRemoved(int featureSetIndex, Feature *feature)
{
qDebug("RadioAstronomy::handleFeatureRemoved: featureSetIndex: %d (%p)", featureSetIndex, feature);
if (m_rotators.contains(feature))
{
m_rotators.remove(feature);
notifyUpdateRotators();
}
}
void RadioAstronomy::handleMessagePipeToBeDeleted(int reason, QObject* object)
{
if ((reason == 0) && m_availableFeatures.contains((Feature*) object)) // producer (feature)
{
qDebug("RadioAstronomy::handleMessagePipeToBeDeleted: removing feature at (%p)", object);
m_availableFeatures.remove((Feature*) object);
notifyUpdateFeatures();
}
}
void RadioAstronomy::handleFeatureMessageQueue(MessageQueue* messageQueue)
{
Message* message;

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015-2018 Edouard Griffiths, F4EXB. //
// Copyright (C) 2021 Jon Beniston, M7RCE //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE //
// //
// 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 //
@ -31,6 +31,7 @@
#include "dsp/basebandsamplesink.h"
#include "channel/channelapi.h"
#include "util/message.h"
#include "availablechannelorfeaturehandler.h"
#include "radioastronomybaseband.h"
#include "radioastronomysettings.h"
@ -329,17 +330,23 @@ public:
MESSAGE_CLASS_DECLARATION
public:
QList<RadioAstronomySettings::AvailableFeature>& getFeatures() { return m_availableFeatures; }
AvailableChannelOrFeatureList& getFeatures() { return m_availableFeatures; }
const QStringList& getRenameFrom() const { return m_renameFrom; }
const QStringList& getRenameTo() const { return m_renameTo; }
static MsgReportAvailableFeatures* create() {
return new MsgReportAvailableFeatures();
static MsgReportAvailableFeatures* create(const QStringList& renameFrom, const QStringList& renameTo) {
return new MsgReportAvailableFeatures(renameFrom, renameTo);
}
private:
QList<RadioAstronomySettings::AvailableFeature> m_availableFeatures;
AvailableChannelOrFeatureList m_availableFeatures;
QStringList m_renameFrom;
QStringList m_renameTo;
MsgReportAvailableFeatures() :
Message()
MsgReportAvailableFeatures(const QStringList& renameFrom, const QStringList& renameTo) :
Message(),
m_renameFrom(renameFrom),
m_renameTo(renameTo)
{}
};
@ -347,17 +354,24 @@ public:
MESSAGE_CLASS_DECLARATION
public:
QList<RadioAstronomySettings::AvailableFeature>& getFeatures() { return m_availableFeatures; }
AvailableChannelOrFeatureList& getFeatures() { return m_availableFeatures; }
const QStringList& getRenameFrom() const { return m_renameFrom; }
const QStringList& getRenameTo() const { return m_renameTo; }
static MsgReportAvailableRotators* create() {
return new MsgReportAvailableRotators();
static MsgReportAvailableRotators* create(const QStringList& renameFrom, const QStringList& renameTo) {
return new MsgReportAvailableRotators(renameFrom, renameTo);
}
private:
QList<RadioAstronomySettings::AvailableFeature> m_availableFeatures;
AvailableChannelOrFeatureList m_availableFeatures;
QStringList m_renameFrom;
QStringList m_renameTo;
MsgReportAvailableRotators() :
Message()
MsgReportAvailableRotators(const QStringList& renameFrom, const QStringList& renameTo) :
Message(),
m_renameFrom(renameFrom),
m_renameTo(renameTo)
{}
};
@ -448,8 +462,10 @@ private:
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
qint64 m_centerFrequency;
QHash<Feature*, RadioAstronomySettings::AvailableFeature> m_availableFeatures;
QHash<Feature*, RadioAstronomySettings::AvailableFeature> m_rotators;
AvailableChannelOrFeatureHandler m_availableFeatureHandler;
AvailableChannelOrFeatureList m_availableFeatures;
AvailableChannelOrFeatureHandler m_availableRotatorHandler;
AvailableChannelOrFeatureList m_rotators;
QObject *m_selectedPipe;
QNetworkAccessManager *m_networkManager;
@ -482,9 +498,8 @@ private:
void sweepStart();
void startCal(bool hot);
void calComplete(MsgCalComplete* report);
void scanAvailableFeatures();
void notifyUpdateFeatures();
void notifyUpdateRotators();
void notifyUpdateFeatures(const QStringList& renameFrom, const QStringList& renameTo);
void notifyUpdateRotators(const QStringList& renameFrom, const QStringList& renameTo);
private slots:
void networkManagerFinished(QNetworkReply *reply);
@ -496,9 +511,8 @@ private slots:
void sweepNext();
void sweepComplete();
void handleIndexInDeviceSetChanged(int index);
void handleFeatureAdded(int featureSetIndex, Feature *feature);
void handleFeatureRemoved(int featureSetIndex, Feature *feature);
void handleMessagePipeToBeDeleted(int reason, QObject* object);
void featuresChanged(const QStringList& renameFrom, const QStringList& renameTo);
void rotatorsChanged(const QStringList& renameFrom, const QStringList& renameTo);
void handleFeatureMessageQueue(MessageQueue* messageQueue);
};

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2021 Jon Beniston, M7RCE //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE //
// //
// 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 //
@ -916,31 +916,33 @@ bool RadioAstronomyGUI::deserialize(const QByteArray& data)
}
}
void RadioAstronomyGUI::updateAvailableFeatures()
void RadioAstronomyGUI::updateAvailableFeatures(const AvailableChannelOrFeatureList& availableFeatures, const QStringList& renameFrom, const QStringList& renameTo)
{
QString currentText = ui->starTracker->currentText();
// Update starTracker settting if it has been renamed
if (renameFrom.contains(m_settings.m_starTracker))
{
m_settings.m_starTracker = renameTo[renameFrom.indexOf(m_settings.m_starTracker)];
applySettings();
}
ui->starTracker->blockSignals(true);
ui->starTracker->clear();
for (const auto& feature : m_availableFeatures) {
ui->starTracker->addItem(tr("F%1:%2 %3").arg(feature.m_featureSetIndex).arg(feature.m_featureIndex).arg(feature.m_type));
for (const auto& feature : availableFeatures) {
ui->starTracker->addItem(feature.getLongId());
}
if (currentText.isEmpty())
{
if (m_availableFeatures.size() > 0) {
ui->starTracker->setCurrentIndex(0);
}
}
else
{
ui->starTracker->setCurrentIndex(ui->starTracker->findText(currentText));
int idx = ui->starTracker->findText(m_settings.m_starTracker);
if (idx >= 0) {
ui->starTracker->setCurrentIndex(idx);
} else {
ui->starTracker->setCurrentIndex(0);
}
ui->starTracker->blockSignals(false);
QString newText = ui->starTracker->currentText();
if (currentText != newText)
QString newText = ui->starTracker->currentText();
if (m_settings.m_starTracker != newText)
{
m_settings.m_starTracker = newText;
applySettings();
@ -970,8 +972,7 @@ bool RadioAstronomyGUI::handleMessage(const Message& message)
{
qDebug("RadioAstronomyGUI::handleMessage: MsgReportAvailableFeatures");
RadioAstronomy::MsgReportAvailableFeatures& report = (RadioAstronomy::MsgReportAvailableFeatures&) message;
m_availableFeatures = report.getFeatures();
updateAvailableFeatures();
updateAvailableFeatures(report.getFeatures(), report.getRenameFrom(), report.getRenameTo());
return true;
}
else if (MainCore::MsgStarTrackerTarget::match(message))
@ -1063,7 +1064,7 @@ bool RadioAstronomyGUI::handleMessage(const Message& message)
else if (RadioAstronomy::MsgReportAvailableRotators::match(message))
{
RadioAstronomy::MsgReportAvailableRotators& report = (RadioAstronomy::MsgReportAvailableRotators&) message;
updateRotatorList(report.getFeatures());
updateRotatorList(report.getFeatures(), report.getRenameFrom(), report.getRenameTo());
return true;
}
@ -1901,11 +1902,11 @@ void RadioAstronomyGUI::on_loadSpectrumData_clicked()
void RadioAstronomyGUI::on_powerTable_cellDoubleClicked(int row, int column)
{
if ((column >= POWER_COL_RA) && (column >= POWER_COL_EL))
if ((column >= POWER_COL_RA) && (column <= POWER_COL_EL))
{
// Display target in Star Tracker
QList<ObjectPipe*> starTrackerPipes;
MainCore::instance()->getMessagePipes().getMessagePipes(this, "startracker.display", starTrackerPipes);
MainCore::instance()->getMessagePipes().getMessagePipes(m_radioAstronomy, "startracker.display", starTrackerPipes);
for (const auto& pipe : starTrackerPipes)
{
@ -2604,17 +2605,22 @@ void RadioAstronomyGUI::tick()
m_tickCount++;
}
void RadioAstronomyGUI::updateRotatorList(const QList<RadioAstronomySettings::AvailableFeature>& rotators)
void RadioAstronomyGUI::updateRotatorList(const AvailableChannelOrFeatureList& rotators, const QStringList& renameFrom, const QStringList& renameTo)
{
// Update rotator settting if it has been renamed
if (renameFrom.contains(m_settings.m_rotator))
{
m_settings.m_rotator = renameTo[renameFrom.indexOf(m_settings.m_rotator)];
applySettings();
}
// Update list of rotators
ui->rotator->blockSignals(true);
ui->rotator->clear();
ui->rotator->addItem("None");
for (const auto& rotator : rotators)
{
QString name = QString("F%1:%2 %3").arg(rotator.m_featureSetIndex).arg(rotator.m_featureIndex).arg(rotator.m_type);
ui->rotator->addItem(name);
for (const auto& rotator : rotators) {
ui->rotator->addItem(rotator.getLongId());
}
// Rotator feature can be created after this plugin, so select it
@ -4335,7 +4341,7 @@ void RadioAstronomyGUI::updateLoSMarker(const QString& name, float l, float b, f
{
// Send to Star Tracker
QList<ObjectPipe*> starTrackerPipes;
MainCore::instance()->getMessagePipes().getMessagePipes(this, "startracker.display", starTrackerPipes);
MainCore::instance()->getMessagePipes().getMessagePipes(m_radioAstronomy, "startracker.display", starTrackerPipes);
for (const auto& pipe : starTrackerPipes)
{
@ -4794,7 +4800,7 @@ void RadioAstronomyGUI::on_spectrumIndex_valueChanged(int value)
// Display target in Star Tracker
QList<ObjectPipe*> starTrackerPipes;
MainCore::instance()->getMessagePipes().getMessagePipes(this, "startracker.display", starTrackerPipes);
MainCore::instance()->getMessagePipes().getMessagePipes(m_radioAstronomy, "startracker.display", starTrackerPipes);
for (const auto& pipe : starTrackerPipes)
{

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2021 Jon Beniston, M7RCE //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE //
// //
// 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 //
@ -235,7 +235,6 @@ private:
RollupState m_rollupState;
RadioAstronomySettings m_settings;
bool m_doApplySettings;
QList<RadioAstronomySettings::AvailableFeature> m_availableFeatures;
int m_basebandSampleRate;
quint64 m_centerFrequency;
@ -351,8 +350,8 @@ private:
void displaySettings();
void displaySpectrumLineFrequency();
void displayRunModeSettings();
void updateAvailableFeatures();
void updateRotatorList(const QList<RadioAstronomySettings::AvailableFeature>& rotators);
void updateAvailableFeatures(const AvailableChannelOrFeatureList& availableFeatures, const QStringList& renameFrom, const QStringList& renameTo);
void updateRotatorList(const AvailableChannelOrFeatureList& rotators, const QStringList& renameFrom, const QStringList& renameTo);
bool handleMessage(const Message& message);
void makeUIConnections();
void updateAbsoluteCenterFrequency();

View File

@ -23,14 +23,6 @@
#include "settings/serializable.h"
#include "radioastronomysettings.h"
const QStringList RadioAstronomySettings::m_pipeTypes = {
QStringLiteral("StarTracker")
};
const QStringList RadioAstronomySettings::m_pipeURIs = {
QStringLiteral("sdrangel.feature.startracker")
};
RadioAstronomySettings::RadioAstronomySettings() :
m_channelMarker(nullptr),
m_rollupState(nullptr)

View File

@ -35,20 +35,6 @@ class Serializable;
struct RadioAstronomySettings
{
struct AvailableFeature
{
int m_featureSetIndex;
int m_featureIndex;
QString m_type;
AvailableFeature() = default;
AvailableFeature(const AvailableFeature&) = default;
AvailableFeature& operator=(const AvailableFeature&) = default;
bool operator==(const AvailableFeature& a) const {
return (m_featureSetIndex == a.m_featureSetIndex) && (m_featureIndex == a.m_featureIndex) && (m_type == a.m_type);
}
};
int m_inputFrequencyOffset;
int m_sampleRate;
int m_rfBandwidth;
@ -244,9 +230,6 @@ struct RadioAstronomySettings
void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
static const QStringList m_pipeTypes;
static const QStringList m_pipeURIs;
};
#endif /* INCLUDE_RADIOASTRONOMYSETTINGS_H */

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2021 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -41,7 +41,8 @@ const char* const AIS::m_featureIdURI = "sdrangel.feature.ais";
const char* const AIS::m_featureId = "AIS";
AIS::AIS(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface)
Feature(m_featureIdURI, webAPIAdapterInterface),
m_availableChannelHandler({"sdrangel.channel.aisdemod"}, QStringList{"ais"})
{
qDebug("AIS::AIS: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
@ -54,23 +55,20 @@ AIS::AIS(WebAPIAdapterInterface *webAPIAdapterInterface) :
this,
&AIS::networkManagerFinished
);
scanAvailableChannels();
QObject::connect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&AIS::handleChannelAdded
);
&AIS::handleChannelMessageQueue);
}
AIS::~AIS()
{
QObject::disconnect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&AIS::handleChannelAdded
);
&AIS::handleChannelMessageQueue);
QObject::disconnect(
m_networkManager,
&QNetworkAccessManager::finished,
@ -362,90 +360,6 @@ void AIS::networkManagerFinished(QNetworkReply *reply)
reply->deleteLater();
}
void AIS::scanAvailableChannels()
{
MainCore *mainCore = MainCore::instance();
MessagePipes& messagePipes = mainCore->getMessagePipes();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
m_availableChannels.clear();
for (const auto& deviceSet : deviceSets)
{
DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine;
if (deviceSourceEngine)
{
for (int chi = 0; chi < deviceSet->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = deviceSet->getChannelAt(chi);
if ((channel->getURI() == "sdrangel.channel.aisdemod") && !m_availableChannels.contains(channel))
{
qDebug("AIS::scanAvailableChannels: register %d:%d (%p)", deviceSet->getIndex(), chi, channel);
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channel, this, "ais");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&AIS::handleMessagePipeToBeDeleted
);
m_availableChannels.insert(channel);
}
}
}
}
}
void AIS::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
qDebug("AIS::handleChannelAdded: deviceSetIndex: %d:%d channel: %s (%p)",
deviceSetIndex, channel->getIndexInDeviceSet(), qPrintable(channel->getURI()), channel);
std::vector<DeviceSet*>& deviceSets = MainCore::instance()->getDeviceSets();
DeviceSet *deviceSet = deviceSets[deviceSetIndex];
DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine;
if (deviceSourceEngine && (channel->getURI() == "sdrangel.channel.aisdemod"))
{
if (!m_availableChannels.contains(channel))
{
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channel, this, "ais");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&AIS::handleMessagePipeToBeDeleted
);
m_availableChannels.insert(channel);
}
}
}
void AIS::handleMessagePipeToBeDeleted(int reason, QObject* object)
{
if ((reason == 0) && m_availableChannels.contains((ChannelAPI*) object)) // producer (channel)
{
qDebug("AIS::handleMessagePipeToBeDeleted: removing channel at (%p)", object);
m_availableChannels.remove((ChannelAPI*) object);
}
}
void AIS::handleChannelMessageQueue(MessageQueue* messageQueue)
{
Message* message;

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
// Copyright (C) 2021-2022 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -25,6 +25,7 @@
#include "feature/feature.h"
#include "util/message.h"
#include "availablechannelorfeaturehandler.h"
#include "aissettings.h"
@ -101,7 +102,8 @@ public:
private:
AISSettings m_settings;
QSet<ChannelAPI*> m_availableChannels;
AvailableChannelOrFeatureHandler m_availableChannelHandler;
AvailableChannelOrFeatureList m_availableChannels;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
@ -110,12 +112,9 @@ private:
void stop();
void applySettings(const AISSettings& settings, const QList<QString>& settingsKeys, bool force = false);
void webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const AISSettings& settings, bool force);
void scanAvailableChannels();
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleMessagePipeToBeDeleted(int reason, QObject* object);
void handleChannelMessageQueue(MessageQueue* messageQueue);
};

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
@ -47,7 +47,7 @@ QStringList AISGUI::m_shipModels = {
"tug_20m.glbe", "tug_30m_1.glbe", "tug_30m_2.glbe", "tug_30m_3.glbe",
"cargo_75m.glbe", "tanker_50m.glbe", "dredger_53m.glbe",
"trawler_22m.glbe",
"speedboat_8m.glbe", "yacht_10m.glbe", "yacht_20m.glbe", "yacht_42m.glbe"
"speedboat_8m.glbe", /*"yacht_10m.glbe",*/ "yacht_20m.glbe", "yacht_42m.glbe"
};
QStringList AISGUI::m_sailboatModels = {
@ -236,6 +236,7 @@ AISGUI::AISGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur
displaySettings();
applySettings(true);
m_resizer.enableChildMouseTracking();
}
AISGUI::~AISGUI()
@ -845,14 +846,14 @@ void AISGUI::getImageAndModel(const QString &type, const QString &shipType, int
{
vessel->m_model = "cargo_75m.glbe";
}
else if (length < 200)
else /*if (length < 200)*/
{
vessel->m_model = "cargo_190m.glbe";
}
else
/*else
{
vessel->m_model = "cargo_230m.glbe";
}
}*/
}
else if (shipType == "Tanker")
{
@ -905,10 +906,10 @@ void AISGUI::getImageAndModel(const QString &type, const QString &shipType, int
{
vessel->m_model = "speedboat_8m.glbe";
}
else if (length < 18)
/*else if (length < 18)
{
vessel->m_model = "yacht_10m.glbe";
}
}*/
else if (length < 32)
{
vessel->m_model = "yacht_20m.glbe";

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
@ -46,7 +46,8 @@ const char* const APRS::m_featureId = "APRS";
APRS::APRS(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_thread(nullptr),
m_worker(nullptr)
m_worker(nullptr),
m_availableChannelHandler(APRSSettings::m_pipeURIs, QStringList{"packets"})
{
qDebug("APRS::APRS: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
@ -59,23 +60,31 @@ APRS::APRS(WebAPIAdapterInterface *webAPIAdapterInterface) :
this,
&APRS::networkManagerFinished
);
scanAvailableChannels();
QObject::connect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&APRS::handleChannelAdded
);
&APRS::handleChannelMessageQueue);
QObject::connect(
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&APRS::channelsChanged);
m_availableChannelHandler.scanAvailableChannelsAndFeatures();
}
APRS::~APRS()
{
QObject::disconnect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&APRS::handleChannelAdded
);
&APRS::handleChannelMessageQueue);
QObject::disconnect(
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&APRS::channelsChanged);
QObject::disconnect(
m_networkManager,
&QNetworkAccessManager::finished,
@ -858,6 +867,7 @@ void APRS::networkManagerFinished(QNetworkReply *reply)
reply->deleteLater();
}
/*
void APRS::scanAvailableChannels()
{
MainCore *mainCore = MainCore::instance();
@ -905,18 +915,25 @@ void APRS::scanAvailableChannels()
}
}
}
*/
void APRS::channelsChanged()
{
m_availableChannels = m_availableChannelHandler.getAvailableChannelOrFeatureList();
notifyUpdateChannels();
}
void APRS::notifyUpdateChannels()
{
if (getMessageQueueToGUI())
{
MsgReportAvailableChannels *msg = MsgReportAvailableChannels::create();
msg->getChannels() = m_availableChannels.values();
msg->getChannels() = m_availableChannels;
getMessageQueueToGUI()->push(msg);
}
}
void APRS::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
/*void APRS::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
qDebug("APRS::handleChannelAdded: deviceSetIndex: %d:%d channel: %s (%p)",
deviceSetIndex, channel->getIndexInDeviceSet(), qPrintable(channel->getURI()), channel);
@ -964,7 +981,7 @@ void APRS::handleMessagePipeToBeDeleted(int reason, QObject* object)
m_availableChannels.remove((ChannelAPI*) object);
notifyUpdateChannels();
}
}
}*/
void APRS::handleChannelMessageQueue(MessageQueue* messageQueue)
{

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
// Copyright (C) 2021-2022 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -26,6 +26,7 @@
#include "feature/feature.h"
#include "util/message.h"
#include "availablechannelorfeaturehandler.h"
#include "aprssettings.h"
@ -104,14 +105,14 @@ public:
MESSAGE_CLASS_DECLARATION
public:
QList<APRSSettings::AvailableChannel>& getChannels() { return m_availableChannels; }
AvailableChannelOrFeatureList& getChannels() { return m_availableChannels; }
static MsgReportAvailableChannels* create() {
return new MsgReportAvailableChannels();
}
private:
QList<APRSSettings::AvailableChannel> m_availableChannels;
AvailableChannelOrFeatureList m_availableChannels;
MsgReportAvailableChannels() :
Message()
@ -160,7 +161,8 @@ private:
QThread *m_thread;
APRSWorker *m_worker;
APRSSettings m_settings;
QHash<ChannelAPI*, APRSSettings::AvailableChannel> m_availableChannels;
AvailableChannelOrFeatureHandler m_availableChannelHandler;
AvailableChannelOrFeatureList m_availableChannels;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
@ -169,14 +171,12 @@ private:
void stop();
void applySettings(const APRSSettings& settings, const QList<QString>& settingsKeys, bool force = false);
void webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const APRSSettings& settings, bool force);
void scanAvailableChannels();
void notifyUpdateChannels();
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleMessagePipeToBeDeleted(int reason, QObject* object);
void handleChannelMessageQueue(MessageQueue* messageQueue);
void channelsChanged();
};
#endif // INCLUDE_FEATURE_APRS_H_

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
@ -708,7 +708,7 @@ void APRSGUI::updateChannelList()
ui->sourcePipes->clear();
for (const auto& channel : m_availableChannels) {
ui->sourcePipes->addItem(tr("R%1:%2 %3").arg(channel.m_deviceSetIndex).arg(channel.m_channelIndex).arg(channel.m_type));
ui->sourcePipes->addItem(channel.getLongId());
}
ui->sourcePipes->blockSignals(false);

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
@ -30,6 +30,7 @@
#include "util/messagequeue.h"
#include "util/aprs.h"
#include "settings/rollupstate.h"
#include "availablechannelorfeature.h"
#include "aprssettings.h"
@ -123,7 +124,7 @@ private:
QList<QString> m_settingsKeys;
RollupState m_rollupState;
bool m_doApplySettings;
QList<APRSSettings::AvailableChannel> m_availableChannels;
AvailableChannelOrFeatureList m_availableChannels;
APRS* m_aprs;
MessageQueue m_inputMessageQueue;

View File

@ -2,7 +2,7 @@
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020-2021 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -38,17 +38,6 @@ class Serializable;
struct APRSSettings
{
struct AvailableChannel
{
int m_deviceSetIndex;
int m_channelIndex;
QString m_type;
AvailableChannel() = default;
AvailableChannel(const AvailableChannel&) = default;
AvailableChannel& operator=(const AvailableChannel&) = default;
};
QString m_igateServer;
int m_igatePort;
QString m_igateCallsign;

View File

@ -48,4 +48,4 @@ APRS icons are from: https://github.com/hessu/aprs-symbols
Full details of the API can be found in the Swagger documentation. Here is a quick example of how to enable the APRS-IS IGate:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "APRS", "APRSSettings": { "igateCallsign": "MYCALLSIGN", "igatePasscode": "12345", "igateFilter": "r/50.2/10.2/25", "igateEnabled": 1 }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/feature/0/settings" -d '{"featureType": "APRS", "APRSSettings": { "igateCallsign": "MYCALLSIGN", "igatePasscode": "12345", "igateFilter": "r/50.2/10.2/25", "igateEnabled": 1 }}'

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
// //
@ -56,6 +56,8 @@ GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface)
Feature(m_featureIdURI, webAPIAdapterInterface),
m_thread(nullptr),
m_worker(nullptr),
m_availableChannelOrFeatureHandler(GS232ControllerSettings::m_pipeURIs),
m_selectedPipe(nullptr),
m_currentAzimuth(0.0f),
m_currentElevation(0.0f)
{
@ -63,7 +65,6 @@ GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface)
setObjectName(m_featureId);
m_state = StIdle;
m_errorMessage = "GS232Controller error";
m_selectedPipe = nullptr;
m_networkManager = new QNetworkAccessManager();
QObject::connect(
m_networkManager,
@ -71,30 +72,21 @@ GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface)
this,
&GS232Controller::networkManagerFinished
);
QObject::connect(
MainCore::instance(),
&MainCore::featureAdded,
&m_availableChannelOrFeatureHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&GS232Controller::handleFeatureAdded
&GS232Controller::channelsOrFeaturesChanged
);
QObject::connect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelOrFeatureHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&GS232Controller::handleChannelAdded
);
QObject::connect(
MainCore::instance(),
&MainCore::featureRemoved,
this,
&GS232Controller::handleFeatureRemoved
);
QObject::connect(
MainCore::instance(),
&MainCore::channelRemoved,
this,
&GS232Controller::handleChannelRemoved
&GS232Controller::handlePipeMessageQueue
);
m_availableChannelOrFeatureHandler.scanAvailableChannelsAndFeatures();
connect(&m_timer, &QTimer::timeout, this, &GS232Controller::scanSerialPorts);
m_timer.start(5000);
}
@ -104,28 +96,16 @@ GS232Controller::~GS232Controller()
m_timer.stop();
disconnect(&m_timer, &QTimer::timeout, this, &GS232Controller::scanSerialPorts);
QObject::disconnect(
MainCore::instance(),
&MainCore::channelRemoved,
&m_availableChannelOrFeatureHandler,
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
this,
&GS232Controller::handleChannelRemoved
&GS232Controller::channelsOrFeaturesChanged
);
QObject::disconnect(
MainCore::instance(),
&MainCore::featureRemoved,
&m_availableChannelOrFeatureHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&GS232Controller::handleFeatureRemoved
);
QObject::disconnect(
MainCore::instance(),
&MainCore::channelAdded,
this,
&GS232Controller::handleChannelAdded
);
QObject::disconnect(
MainCore::instance(),
&MainCore::featureAdded,
this,
&GS232Controller::handleFeatureAdded
&GS232Controller::handlePipeMessageQueue
);
QObject::disconnect(
m_networkManager,
@ -154,8 +134,6 @@ void GS232Controller::start()
GS232ControllerWorker::MsgConfigureGS232ControllerWorker *msg =
GS232ControllerWorker::MsgConfigureGS232ControllerWorker::create(m_settings, QList<QString>(), true);
m_worker->getInputMessageQueue()->push(msg);
scanAvailableChannelsAndFeatures();
}
void GS232Controller::stop()
@ -210,7 +188,7 @@ bool GS232Controller::handleMessage(const Message& cmd)
}
else if (MsgScanAvailableChannelOrFeatures::match(cmd))
{
scanAvailableChannelsAndFeatures();
notifyUpdate({}, {});
return true;
}
else if (GS232ControllerReport::MsgReportAzAl::match(cmd))
@ -248,8 +226,6 @@ bool GS232Controller::handleMessage(const Message& cmd)
applySettings(m_settings, QList<QString>{"azimuth", "elevation"});
}
}
else
qDebug() << "GS232Controller::handleMessage: No match " << msg.getPipeSource() << " " << m_selectedPipe;
}
return true;
}
@ -306,10 +282,6 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, con
{
qDebug() << "GS232Controller::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force;
// if ((m_settings.m_source != settings.m_source)
// || (!settings.m_source.isEmpty() && (m_selectedPipe == nullptr)) // Change in available pipes
// || force)
if (settingsKeys.contains("source")
|| (!settings.m_source.isEmpty() && (m_selectedPipe == nullptr)) // Change in available pipes
|| force)
@ -317,27 +289,24 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, con
MainCore *mainCore = MainCore::instance();
MessagePipes& messagePipes = mainCore->getMessagePipes();
if (m_selectedPipe)
m_availableChannelOrFeatureHandler.deregisterPipes(m_selectedPipe, this, {"target"});
/*if (m_selectedPipe)
{
qDebug("GS232Controller::applySettings: unregister %s (%p)", qPrintable(m_selectedPipe->objectName()), m_selectedPipe);
// Don't deref m_selectedPipe, as plugin may have been deleted
qDebug("GS232Controller::applySettings: unregister (%p)", m_selectedPipe);
messagePipes.unregisterProducerToConsumer(m_selectedPipe, this, "target");
}
}*/
if (!settings.m_source.isEmpty())
m_selectedPipe = m_availableChannelOrFeatureHandler.registerPipes(settings.m_source, this, {"target"});
/*if (!settings.m_source.isEmpty())
{
QObject *object = nullptr;
int index = m_availableChannelOrFeatures.indexOfLongId(settings.m_source);
for (const auto& oval : m_availableChannelOrFeatures)
{
if (settings.m_source == oval.getLongId())
{
object = oval.m_object;
break;
}
}
if (object)
if (index >= 0)
{
QObject *object = m_availableChannelOrFeatures[index].m_object;
registerPipe(object);
m_selectedPipe = object;
}
@ -350,7 +319,7 @@ void GS232Controller::applySettings(const GS232ControllerSettings& settings, con
else
{
m_selectedPipe = nullptr;
}
}*/
}
GS232ControllerWorker::MsgConfigureGS232ControllerWorker *msg = GS232ControllerWorker::MsgConfigureGS232ControllerWorker::create(
@ -718,12 +687,7 @@ void GS232Controller::webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& r
for (const auto& item : m_availableChannelOrFeatures)
{
QString itemText = tr("%1%2:%3 %4")
.arg(item.m_kind)
.arg(item.m_superIndex)
.arg(item.m_index)
.arg(item.m_type);
QString itemText = item.getLongId();
response.getGs232ControllerReport()->getSources()->append(new QString(itemText));
}
@ -763,69 +727,22 @@ void GS232Controller::networkManagerFinished(QNetworkReply *reply)
reply->deleteLater();
}
void GS232Controller::scanAvailableChannelsAndFeatures()
void GS232Controller::channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo)
{
m_availableChannelOrFeatures = MainCore::instance()->getAvailableChannelsAndFeatures(GS232ControllerSettings::m_pipeURIs);
notifyUpdate();
m_availableChannelOrFeatures = m_availableChannelOrFeatureHandler.getAvailableChannelOrFeatureList();
notifyUpdate(renameFrom, renameTo);
}
void GS232Controller::notifyUpdate()
void GS232Controller::notifyUpdate(const QStringList& renameFrom, const QStringList& renameTo)
{
if (getMessageQueueToGUI())
{
MsgReportAvailableChannelOrFeatures *msg = MsgReportAvailableChannelOrFeatures::create();
MsgReportAvailableChannelOrFeatures *msg = MsgReportAvailableChannelOrFeatures::create(renameFrom, renameTo);
msg->getItems() = m_availableChannelOrFeatures;
getMessageQueueToGUI()->push(msg);
}
}
void GS232Controller::handleFeatureAdded(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
scanAvailableChannelsAndFeatures();
}
void GS232Controller::handleFeatureRemoved(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
scanAvailableChannelsAndFeatures();
}
void GS232Controller::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
(void) deviceSetIndex;
(void) channel;
scanAvailableChannelsAndFeatures();
}
void GS232Controller::handleChannelRemoved(int deviceSetIndex, ChannelAPI *channel)
{
(void) deviceSetIndex;
(void) channel;
scanAvailableChannelsAndFeatures();
}
void GS232Controller::registerPipe(QObject *object)
{
qDebug("GS232Controller::registerPipe: register %s (%p)", qPrintable(object->objectName()), object);
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(object, this, "target");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handlePipeMessageQueue(messageQueue); },
Qt::QueuedConnection
);
}
void GS232Controller::handlePipeMessageQueue(MessageQueue* messageQueue)
{
Message* message;

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
// //
@ -27,6 +27,7 @@
#include "feature/feature.h"
#include "util/message.h"
#include "availablechannelorfeaturehandler.h"
#include "maincore.h"
#include "gs232controllersettings.h"
@ -111,17 +112,23 @@ public:
MESSAGE_CLASS_DECLARATION
public:
QList<MainCore::AvailableChannelOrFeature>& getItems() { return m_availableChannelOrFeatures; }
AvailableChannelOrFeatureList& getItems() { return m_availableChannelOrFeatures; }
const QStringList& getRenameFrom() const { return m_renameFrom; }
const QStringList& getRenameTo() const { return m_renameTo; }
static MsgReportAvailableChannelOrFeatures* create() {
return new MsgReportAvailableChannelOrFeatures();
static MsgReportAvailableChannelOrFeatures* create(const QStringList& renameFrom, const QStringList& renameTo) {
return new MsgReportAvailableChannelOrFeatures(renameFrom, renameTo);
}
private:
QList<MainCore::AvailableChannelOrFeature> m_availableChannelOrFeatures;
AvailableChannelOrFeatureList m_availableChannelOrFeatures;
QStringList m_renameFrom;
QStringList m_renameTo;
MsgReportAvailableChannelOrFeatures() :
Message()
MsgReportAvailableChannelOrFeatures(const QStringList& renameFrom, const QStringList& renameTo) :
Message(),
m_renameFrom(renameFrom),
m_renameTo(renameTo)
{}
};
@ -213,8 +220,8 @@ private:
QThread *m_thread;
GS232ControllerWorker *m_worker;
GS232ControllerSettings m_settings;
//QHash<QObject*, GS232ControllerSettings::AvailableChannelOrFeature> m_availableChannelOrFeatures;
QList<MainCore::AvailableChannelOrFeature> m_availableChannelOrFeatures;
AvailableChannelOrFeatureList m_availableChannelOrFeatures;
AvailableChannelOrFeatureHandler m_availableChannelOrFeatureHandler;
QObject *m_selectedPipe;
QTimer m_timer;
@ -231,17 +238,11 @@ private:
void applySettings(const GS232ControllerSettings& settings, const QList<QString>& settingsKeys, bool force = false);
void webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const GS232ControllerSettings& settings, bool force);
void webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response);
void scanAvailableChannelsAndFeatures();
void notifyUpdate();
void registerPipe(QObject *object);
void notifyUpdate(const QStringList& renameFrom, const QStringList& renameTo);
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleFeatureAdded(int featureSetIndex, Feature *feature);
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleFeatureRemoved(int featureSetIndex, Feature *feature);
void handleChannelRemoved(int deviceSetIndex, ChannelAPI *feature);
//void handleMessagePipeToBeDeleted(int reason, QObject* object);
void channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo);
void handlePipeMessageQueue(MessageQueue* messageQueue);
void scanSerialPorts();
};

View File

@ -51,7 +51,7 @@ void GS232ControllerGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
applyAllSettings();
}
QByteArray GS232ControllerGUI::serialize() const
@ -65,7 +65,7 @@ bool GS232ControllerGUI::deserialize(const QByteArray& data)
{
m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex);
displaySettings();
applySettings(true);
applyAllSettings();
return true;
}
else
@ -121,9 +121,7 @@ void GS232ControllerGUI::displayToAzEl(float coord1, float coord2)
m_settings.m_azimuth = coord1;
m_settings.m_elevation = coord2;
}
m_settingsKeys.append("azimuth");
m_settingsKeys.append("elevation");
applySettings();
applySettings({"azimuth", "elevation"});
}
bool GS232ControllerGUI::handleMessage(const Message& message)
@ -149,7 +147,7 @@ bool GS232ControllerGUI::handleMessage(const Message& message)
{
GS232Controller::MsgReportAvailableChannelOrFeatures& report =
(GS232Controller::MsgReportAvailableChannelOrFeatures&) message;
updatePipeList(report.getItems());
updatePipeList(report.getItems(), report.getRenameFrom(), report.getRenameTo());
return true;
}
else if (GS232ControllerReport::MsgReportAzAl::match(message))
@ -206,7 +204,7 @@ void GS232ControllerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
(void) rollDown;
getRollupContents()->saveState(m_rollupState);
applySettings();
applySetting("rollupState");
}
GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
@ -260,7 +258,7 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu
connect(&m_inputTimer, &QTimer::timeout, this, &GS232ControllerGUI::checkInputController);
displaySettings();
applySettings(true);
applyAllSettings();
makeUIConnections();
// Get pre-existing pipes
@ -408,8 +406,7 @@ void GS232ControllerGUI::on_inputController_currentIndexChanged(int index)
if (index >= 0)
{
m_settings.m_inputController = ui->inputController->currentText();
m_settingsKeys.append("inputController");
applySettings();
applySetting("inputController");
updateInputController();
}
}
@ -425,28 +422,24 @@ void GS232ControllerGUI::on_highSensitivity_clicked(bool checked)
{
m_settings.m_highSensitivity = checked;
ui->highSensitivity->setText(checked ? "H" : "L");
m_settingsKeys.append("highSensitivity");
applySettings();
applySetting("highSensitivity");
}
void GS232ControllerGUI::on_enableTargetControl_clicked(bool checked)
{
m_settings.m_targetControlEnabled = checked;
m_settingsKeys.append("targetControlEnabled");
applySettings();
applySetting("targetControlEnabled");
}
void GS232ControllerGUI::on_enableOffsetControl_clicked(bool checked)
{
m_settings.m_offsetControlEnabled = checked;
m_settingsKeys.append("offsetControlEnabled");
applySettings();
applySetting("offsetControlEnabled");
}
void GS232ControllerGUI::inputConfigurationComplete()
{
m_settingsKeys.append("inputControllerSettings");
applySettings();
applySetting("inputControllerSettings");
}
GS232ControllerGUI::~GS232ControllerGUI()
@ -546,10 +539,16 @@ void GS232ControllerGUI::updateSerialPortList(const QStringList& serialPorts)
ui->serialPort->blockSignals(false);
}
void GS232ControllerGUI::updatePipeList(const QList<MainCore::AvailableChannelOrFeature>& sources)
void GS232ControllerGUI::updatePipeList(const AvailableChannelOrFeatureList& sources, const QStringList& renameFrom, const QStringList& renameTo)
{
QString currentText = ui->sources->currentText();
QString newText;
// Update source settting if it has been renamed
if (renameFrom.contains(m_settings.m_source))
{
m_settings.m_source = renameTo[renameFrom.indexOf(m_settings.m_source)];
applySetting("source");
}
int prevIdx = ui->sources->currentIndex();
ui->sources->blockSignals(true);
ui->sources->clear();
@ -557,40 +556,33 @@ void GS232ControllerGUI::updatePipeList(const QList<MainCore::AvailableChannelOr
ui->sources->addItem(source.getLongId());
}
int index = ui->sources->findText(m_settings.m_source);
ui->sources->setCurrentIndex(index);
if (index < 0) // current source is not found
// Select current setting, if it exists
// If not, and no prior setting, make sure nothing selected, as channel/feature may be created later on
// If not found and something was previously selected, clear the setting, as probably deleted
int idx = ui->sources->findText(m_settings.m_source);
if (idx >= 0)
{
ui->sources->setCurrentIndex(idx);
}
else if (prevIdx == -1)
{
ui->sources->setCurrentIndex(-1);
}
else
{
m_settings.m_source = "";
applySetting("source");
ui->targetName->setText("");
m_settingsKeys.append("source");
applySettings();
}
// if (currentText.isEmpty())
// {
// // Source feature may be loaded after this, so may not have existed when
// // displaySettings was called
// if (sources.size() > 0) {
// ui->sources->setCurrentIndex(ui->sources->findText(m_settings.m_source));
// }
// }
// else
// {
// ui->sources->setCurrentIndex(ui->sources->findText(currentText));
// }
ui->sources->blockSignals(false);
// QString newText = ui->sources->currentText();
// if (currentText != newText)
// {
// m_settings.m_source = newText;
// ui->targetName->setText("");
// applySettings();
// }
// If no current settting, select first available
if (m_settings.m_source.isEmpty() && (ui->sources->count() > 0))
{
ui->sources->setCurrentIndex(0);
on_sources_currentTextChanged(ui->sources->currentText());
}
}
void GS232ControllerGUI::onMenuDialogCalled(const QPoint &p)
@ -620,15 +612,17 @@ void GS232ControllerGUI::onMenuDialogCalled(const QPoint &p)
setTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
m_settingsKeys.append("title");
m_settingsKeys.append("rgbColor");
m_settingsKeys.append("useReverseAPI");
m_settingsKeys.append("reverseAPIAddress");
m_settingsKeys.append("reverseAPIPort");
m_settingsKeys.append("reverseAPIFeatureSetIndex");
m_settingsKeys.append("reverseAPIFeatureIndex");
QList<QString> settingsKeys({
"rgbColor",
"title",
"useReverseAPI",
"reverseAPIAddress",
"reverseAPIPort",
"reverseAPIDeviceIndex",
"reverseAPIChannelIndex"
});
applySettings();
applySettings(settingsKeys);
}
resetContextMenuType();
@ -698,15 +692,13 @@ void GS232ControllerGUI::on_protocol_currentIndexChanged(int index)
{
m_settings.m_protocol = (GS232ControllerSettings::Protocol)index;
setProtocol(m_settings.m_protocol);
m_settingsKeys.append("protocol");
applySettings();
applySetting("protocol");
}
void GS232ControllerGUI::on_connection_currentIndexChanged(int index)
{
m_settings.m_connection = (GS232ControllerSettings::Connection)index;
m_settingsKeys.append("connection");
applySettings();
applySetting("connection");
updateConnectionWidgets();
}
@ -714,30 +706,26 @@ void GS232ControllerGUI::on_serialPort_currentIndexChanged(int index)
{
(void) index;
m_settings.m_serialPort = ui->serialPort->currentText();
m_settingsKeys.append("serialPort");
applySettings();
applySetting("serialPort");
}
void GS232ControllerGUI::on_baudRate_currentIndexChanged(int index)
{
(void) index;
m_settings.m_baudRate = ui->baudRate->currentText().toInt();
m_settingsKeys.append("baudRate");
applySettings();
applySetting("baudRate");
}
void GS232ControllerGUI::on_host_editingFinished()
{
m_settings.m_host = ui->host->text();
m_settingsKeys.append("host");
applySettings();
applySetting("host");
}
void GS232ControllerGUI::on_port_valueChanged(int value)
{
m_settings.m_port = value;
m_settingsKeys.append("port");
applySettings();
applySetting("port");
}
void GS232ControllerGUI::on_coord1_valueChanged(double value)
@ -764,8 +752,7 @@ void GS232ControllerGUI::on_azimuthOffset_valueChanged(double value)
m_inputAzOffset = value;
}
m_settings.m_azimuthOffset = (float) value;
m_settingsKeys.append("azimuthOffset");
applySettings();
applySetting("azimuthOffset");
}
void GS232ControllerGUI::on_elevationOffset_valueChanged(double value)
@ -774,58 +761,50 @@ void GS232ControllerGUI::on_elevationOffset_valueChanged(double value)
m_inputElOffset = value;
}
m_settings.m_elevationOffset = (float) value;
m_settingsKeys.append("elevationOffset");
applySettings();
applySetting("elevationOffset");
}
void GS232ControllerGUI::on_azimuthMin_valueChanged(int value)
{
m_settings.m_azimuthMin = value;
m_settingsKeys.append("azimuthMin");
applySettings();
applySetting("azimuthMin");
}
void GS232ControllerGUI::on_azimuthMax_valueChanged(int value)
{
m_settings.m_azimuthMax = value;
m_settingsKeys.append("azimuthMax");
applySettings();
applySetting("azimuthMax");
}
void GS232ControllerGUI::on_elevationMin_valueChanged(int value)
{
m_settings.m_elevationMin = value;
m_settingsKeys.append("elevationMin");
applySettings();
applySetting("elevationMin");
}
void GS232ControllerGUI::on_elevationMax_valueChanged(int value)
{
m_settings.m_elevationMax = value;
m_settingsKeys.append("elevationMax");
applySettings();
applySetting("elevationMax");
}
void GS232ControllerGUI::on_tolerance_valueChanged(double value)
{
m_settings.m_tolerance = value;
m_settingsKeys.append("tolerance");
applySettings();
applySetting("tolerance");
}
void GS232ControllerGUI::on_precision_valueChanged(int value)
{
m_settings.m_precision = value;
setPrecision();
m_settingsKeys.append("precision");
applySettings();
applySetting("precision");
}
void GS232ControllerGUI::on_coordinates_currentIndexChanged(int index)
{
m_settings.m_coordinates = (GS232ControllerSettings::Coordinates)index;
m_settingsKeys.append("coordinates");
applySettings();
applySetting("coordinates");
float coord1, coord2;
azElToDisplay(m_settings.m_azimuth, m_settings.m_elevation, coord1, coord2);
@ -880,8 +859,7 @@ void GS232ControllerGUI::on_track_stateChanged(int state)
ui->targetName->setText("");
}
m_settingsKeys.append("track");
applySettings();
applySetting("track");
}
void GS232ControllerGUI::on_sources_currentTextChanged(const QString& text)
@ -889,36 +867,31 @@ void GS232ControllerGUI::on_sources_currentTextChanged(const QString& text)
qDebug("GS232ControllerGUI::on_sources_currentTextChanged: %s", qPrintable(text));
m_settings.m_source = text;
ui->targetName->setText("");
m_settingsKeys.append("source");
applySettings();
applySetting("source");
}
void GS232ControllerGUI::on_dfmTrack_clicked(bool checked)
{
m_settings.m_dfmTrackOn = checked;
m_settingsKeys.append("dfmTrackOn");
applySettings();
applySetting("dfmTrackOn");
}
void GS232ControllerGUI::on_dfmLubePumps_clicked(bool checked)
{
m_settings.m_dfmLubePumpsOn = checked;
m_settingsKeys.append("dfmLubePumpsOn");
applySettings();
applySetting("dfmLubePumpsOn");
}
void GS232ControllerGUI::on_dfmBrakes_clicked(bool checked)
{
m_settings.m_dfmBrakesOn = checked;
m_settingsKeys.append("dfmBrakesOn");
applySettings();
applySetting("dfmBrakesOn");
}
void GS232ControllerGUI::on_dfmDrives_clicked(bool checked)
{
m_settings.m_dfmDrivesOn = checked;
m_settingsKeys.append("dfmDrivesOn");
applySettings();
applySetting("dfmDrivesOn");
}
void GS232ControllerGUI::on_dfmShowStatus_clicked()
@ -983,17 +956,28 @@ void GS232ControllerGUI::updateStatus()
}
}
void GS232ControllerGUI::applySettings(bool force)
void GS232ControllerGUI::applySetting(const QString& settingsKey)
{
applySettings({settingsKey});
}
void GS232ControllerGUI::applySettings(const QStringList& settingsKeys, bool force)
{
m_settingsKeys.append(settingsKeys);
if (m_doApplySettings)
{
GS232Controller::MsgConfigureGS232Controller* message = GS232Controller::MsgConfigureGS232Controller::create(m_settings, m_settingsKeys, force);
m_gs232Controller->getInputMessageQueue()->push(message);
m_settingsKeys.clear();
}
m_settingsKeys.clear();
}
void GS232ControllerGUI::applyAllSettings()
{
applySettings(QStringList(), true);
}
void GS232ControllerGUI::makeUIConnections()
{
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &GS232ControllerGUI::on_startStop_toggled);

View File

@ -85,12 +85,14 @@ private:
virtual ~GS232ControllerGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void applySetting(const QString& settingsKey);
void applySettings(const QStringList& settingsKeys, bool force = false);
void applyAllSettings();
void displaySettings();
void setProtocol(GS232ControllerSettings::Protocol protocol);
void setPrecision();
void updateConnectionWidgets();
void updatePipeList(const QList<MainCore::AvailableChannelOrFeature>& sources);
void updatePipeList(const AvailableChannelOrFeatureList& sources, const QStringList& renameFrom, const QStringList& renameTo);
void updateSerialPortList();
void updateSerialPortList(const QStringList& serialPorts);
bool handleMessage(const Message& message);

View File

@ -2,7 +2,7 @@
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-2017, 2019-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020-2021, 2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2021, 2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -26,14 +26,6 @@
#include "gs232controllersettings.h"
#include "inputcontrollersettings.h"
const QStringList GS232ControllerSettings::m_pipeTypes = {
QStringLiteral("ADSBDemod"),
QStringLiteral("Map"),
QStringLiteral("SkyMap"),
QStringLiteral("StarTracker"),
QStringLiteral("SatelliteTracker")
};
const QStringList GS232ControllerSettings::m_pipeURIs = {
QStringLiteral("sdrangel.channel.adsbdemod"),
QStringLiteral("sdrangel.feature.map"),

View File

@ -2,7 +2,7 @@
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020-2021, 2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2021, 2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -81,7 +81,6 @@ struct GS232ControllerSettings
void applySettings(const QStringList& settingsKeys, const GS232ControllerSettings& settings);
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
static const QStringList m_pipeTypes;
static const QStringList m_pipeURIs;
};

View File

@ -185,8 +185,8 @@ The controller uses the 'P' and 'p' commands to set and get azimuth and elevatio
Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the azimuth and elevation from the command line:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "GS232Controller", "GS232ControllerSettings": { "azimuth": 180, "elevation": 45 }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/feature/0/settings" -d '{"featureType": "GS232Controller", "GS232ControllerSettings": { "azimuth": 180, "elevation": 45 }}'
To start sending commands to the rotator:
curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/run"
curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/feature/0/run"

View File

@ -97,8 +97,8 @@ The statistics fields display the statistics for the current test:
Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the azimuth and elevation from the command line:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "PERTester", "PERTesterSettings": { "packetCount": 100 }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/feature/0/settings" -d '{"featureType": "PERTester", "PERTesterSettings": { "packetCount": 100 }}'
To start sending the test:
curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/run"
curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/feature/0/run"

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2021-2022 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -41,7 +41,8 @@ const char* const Radiosonde::m_featureIdURI = "sdrangel.feature.radiosonde";
const char* const Radiosonde::m_featureId = "Radiosonde";
Radiosonde::Radiosonde(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface)
Feature(m_featureIdURI, webAPIAdapterInterface),
m_availableChannelHandler({"sdrangel.channel.radiosondedemod"}, QStringList{"radiosonde"})
{
qDebug("Radiosonde::Radiosonde: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
@ -54,22 +55,22 @@ Radiosonde::Radiosonde(WebAPIAdapterInterface *webAPIAdapterInterface) :
this,
&Radiosonde::networkManagerFinished
);
scanAvailableChannels();
QObject::connect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&Radiosonde::handleChannelAdded
);
&Radiosonde::handleChannelMessageQueue);
m_availableChannelHandler.scanAvailableChannelsAndFeatures();
}
Radiosonde::~Radiosonde()
{
QObject::disconnect(
MainCore::instance(),
&MainCore::channelAdded,
&m_availableChannelHandler,
&AvailableChannelOrFeatureHandler::messageEnqueued,
this,
&Radiosonde::handleChannelAdded
&Radiosonde::handleChannelMessageQueue
);
QObject::disconnect(
m_networkManager,
@ -362,90 +363,6 @@ void Radiosonde::networkManagerFinished(QNetworkReply *reply)
reply->deleteLater();
}
void Radiosonde::scanAvailableChannels()
{
MainCore *mainCore = MainCore::instance();
MessagePipes& messagePipes = mainCore->getMessagePipes();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
m_availableChannels.clear();
for (const auto& deviceSet : deviceSets)
{
DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine;
if (deviceSourceEngine)
{
for (int chi = 0; chi < deviceSet->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = deviceSet->getChannelAt(chi);
if ((channel->getURI() == "sdrangel.channel.radiosondedemod") && !m_availableChannels.contains(channel))
{
qDebug("Radiosonde::scanAvailableChannels: register %d:%d (%p)", deviceSet->getIndex(), chi, channel);
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channel, this, "radiosonde");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&Radiosonde::handleMessagePipeToBeDeleted
);
m_availableChannels.insert(channel);
}
}
}
}
}
void Radiosonde::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
qDebug("Radiosonde::handleChannelAdded: deviceSetIndex: %d:%d channel: %s (%p)",
deviceSetIndex, channel->getIndexInDeviceSet(), qPrintable(channel->getURI()), channel);
std::vector<DeviceSet*>& deviceSets = MainCore::instance()->getDeviceSets();
DeviceSet *deviceSet = deviceSets[deviceSetIndex];
DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine;
if (deviceSourceEngine && (channel->getURI() == "sdrangel.channel.radiosondedemod"))
{
if (!m_availableChannels.contains(channel))
{
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channel, this, "radiosonde");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&Radiosonde::handleMessagePipeToBeDeleted
);
m_availableChannels.insert(channel);
}
}
}
void Radiosonde::handleMessagePipeToBeDeleted(int reason, QObject* object)
{
if ((reason == 0) && m_availableChannels.contains((ChannelAPI*) object)) // producer (channel)
{
qDebug("Radiosonde::handleMessagePipeToBeDeleted: removing channel at (%p)", object);
m_availableChannels.remove((ChannelAPI*) object);
}
}
void Radiosonde::handleChannelMessageQueue(MessageQueue* messageQueue)
{
Message* message;

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
// Copyright (C) 2021-2022 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -25,6 +25,7 @@
#include "feature/feature.h"
#include "util/message.h"
#include "availablechannelorfeaturehandler.h"
#include "radiosondesettings.h"
@ -101,7 +102,8 @@ public:
private:
RadiosondeSettings m_settings;
QSet<ChannelAPI*> m_availableChannels;
AvailableChannelOrFeatureHandler m_availableChannelHandler;
AvailableChannelOrFeatureList m_availableChannels;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
@ -110,12 +112,9 @@ private:
void stop();
void applySettings(const RadiosondeSettings& settings, const QList<QString>& settingsKeys, bool force = false);
void webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const RadiosondeSettings& settings, bool force);
void scanAvailableChannels();
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleMessagePipeToBeDeleted(int reason, QObject* object);
void handleChannelMessageQueue(MessageQueue* messageQueue);
};

View File

@ -216,12 +216,12 @@ Icons are by Freepik from Flaticon https://www.flaticon.com/
Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the satellites to track:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "SatelliteTracker", "SatelliteTrackerSettings": { "satellites": [ "NOAA 15", "NOAA 19" ] }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/feature/0/settings" -d '{"featureType": "SatelliteTracker", "SatelliteTrackerSettings": { "satellites": [ "NOAA 15", "NOAA 19" ] }}'
And how to set the target:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "SatelliteTracker", "SatelliteTrackerSettings": { "target": "NOAA 15" }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/feature/0/settings" -d '{"featureType": "SatelliteTracker", "SatelliteTrackerSettings": { "target": "NOAA 15" }}'
Or, to set the device settings:
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "SatelliteTracker", "SatelliteTrackerSettings": { "deviceSettings": [ { "satellite": "ISS", "deviceSettings": [ { "deviceSet": "R0", "doppler": [0], "frequency": 0, "presetDescription": Sat", "presetFrequency": 145.825, "presetGroup": "ISS Digi", "startOnAOS": 1, "startStopFileSinks": 1, "stopOnLOS": 1}] } ] }}'
curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/feature/0/settings" -d '{"featureType": "SatelliteTracker", "SatelliteTrackerSettings": { "deviceSettings": [ { "satellite": "ISS", "deviceSettings": [ { "deviceSet": "R0", "doppler": [0], "frequency": 0, "presetDescription": Sat", "presetFrequency": 145.825, "presetGroup": "ISS Digi", "startOnAOS": 1, "startStopFileSinks": 1, "stopOnLOS": 1}] } ] }}'

View File

@ -9,8 +9,8 @@
<script type="text/javascript">
var esaskyFrame;
var antennaHpbw = 5.0;
var showAntenna = false;
var antennaHpbw = 5.0;
var showAntenna = false;
// API reference: https://www.cosmos.esa.int/web/esdc/esasky-javascript-api
function on_ready() {
@ -145,26 +145,26 @@
function showAntennaFoV(ra, dec) {
var cmd =
{
{
event: 'overlayFootprints',
content: {
'overlaySet':
{
'type': 'FootprintListOverlay',
'overlayName': 'Antenna FoV',
'cooframe': 'J2000',
'color': 'white',
'lineWidth': 5,
'skyObjectList': [
{
'name': 'Antenna FoV',
'id': 1,
'stcs': 'CIRCLE J2000 ' + ra + ' ' + dec + ' ' + (antennaHpbw / 2.0),
'ra_deg': ra,
'dec_deg': dec
}]
}
}
content: {
'overlaySet':
{
'type': 'FootprintListOverlay',
'overlayName': 'Antenna FoV',
'cooframe': 'J2000',
'color': 'white',
'lineWidth': 5,
'skyObjectList': [
{
'name': 'Antenna FoV',
'id': 1,
'stcs': 'CIRCLE J2000 ' + ra + ' ' + dec + ' ' + (antennaHpbw / 2.0),
'ra_deg': ra,
'dec_deg': dec
}]
}
}
};
esaskyFrame.contentWindow.postMessage(cmd, 'https://sky.esa.int');
}

View File

@ -190,6 +190,7 @@ void SkyMapGUI::onWidgetRolled(QWidget* widget, bool rollDown)
(void) rollDown;
getRollupContents()->saveState(m_rollupState);
applySetting("rollupState");
}
SkyMapGUI::SkyMapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
@ -198,7 +199,8 @@ SkyMapGUI::SkyMapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *
m_pluginAPI(pluginAPI),
m_featureUISet(featureUISet),
m_doApplySettings(true),
m_source(nullptr)
m_source(nullptr),
m_availableChannelOrFeatureHandler(SkyMapSettings::m_pipeURIs, {"target", "skymap.target"})
{
m_feature = feature;
setAttribute(Qt::WA_DeleteOnClose, true);
@ -255,11 +257,8 @@ SkyMapGUI::SkyMapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *
makeUIConnections();
m_resizer.enableChildMouseTracking();
QObject::connect(MainCore::instance(), &MainCore::featureAdded, this, &SkyMapGUI::handleFeatureAdded);
QObject::connect(MainCore::instance(), &MainCore::channelAdded, this, &SkyMapGUI::handleChannelAdded);
QObject::connect(MainCore::instance(), &MainCore::featureRemoved, this, &SkyMapGUI::handleFeatureRemoved);
QObject::connect(MainCore::instance(), &MainCore::channelRemoved, this, &SkyMapGUI::handleChannelRemoved);
updateSourceList();
QObject::connect(&m_availableChannelOrFeatureHandler, &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged, this, &SkyMapGUI::updateSourceList);
m_availableChannelOrFeatureHandler.scanAvailableChannelsAndFeatures();
connect(&m_wtml, &WTML::dataUpdated, this, &SkyMapGUI::wtmlUpdated);
m_wtml.getData();
@ -267,11 +266,7 @@ SkyMapGUI::SkyMapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *
SkyMapGUI::~SkyMapGUI()
{
QObject::disconnect(MainCore::instance(), &MainCore::featureAdded, this, &SkyMapGUI::handleFeatureAdded);
QObject::disconnect(MainCore::instance(), &MainCore::channelAdded, this, &SkyMapGUI::handleChannelAdded);
QObject::disconnect(MainCore::instance(), &MainCore::featureRemoved, this, &SkyMapGUI::handleFeatureRemoved);
QObject::disconnect(MainCore::instance(), &MainCore::channelRemoved, this, &SkyMapGUI::handleChannelRemoved);
QObject::disconnect(&m_availableChannelOrFeatureHandler, &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged, this, &SkyMapGUI::updateSourceList);
if (m_webServer)
{
m_webServer->close();
@ -350,7 +345,6 @@ void SkyMapGUI::on_source_currentIndexChanged(int index)
}
}
void SkyMapGUI::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode)
{
qDebug() << "SkyMapGUI::renderProcessTerminated: " << terminationStatus << "exitCode" << exitCode;
@ -472,22 +466,17 @@ void SkyMapGUI::applySetting(const QString& settingsKey)
void SkyMapGUI::applySettings(const QStringList& settingsKeys, bool force)
{
m_settingsKeys.append(settingsKeys);
if (m_doApplySettings)
{
SkyMap::MsgConfigureSkyMap* message = SkyMap::MsgConfigureSkyMap::create(m_settings, settingsKeys, force);
SkyMap::MsgConfigureSkyMap* message = SkyMap::MsgConfigureSkyMap::create(m_settings, m_settingsKeys, force);
m_skymap->getInputMessageQueue()->push(message);
m_settingsKeys.clear();
m_availableChannelOrFeatureHandler.deregisterPipes(m_source, this, {"target", "skymap.target"});
QObject *oldSource = m_source;
QObject *source = MainCore::getAvailableChannelOrFeatureByLongId(m_settings.m_source, m_availableChannelOrFeatures);
if (source)
{
registerPipe(source);
m_source = source;
}
else
{
m_source = nullptr;
}
m_source = m_availableChannelOrFeatureHandler.registerPipes(m_settings.m_source, this, {"target", "skymap.target"});
// When we change plugins, default to current date and time and My Position, until we get something different
if (oldSource && !m_source)
@ -497,6 +486,7 @@ void SkyMapGUI::applySettings(const QStringList& settingsKeys, bool force)
MainCore::instance()->getSettings().getLongitude(),
MainCore::instance()->getSettings().getAltitude());
}
}
}
@ -784,91 +774,85 @@ void SkyMapGUI::receivedEvent(const QJsonObject &obj)
}
}
// Loaded via WTML
QStringList wwtBackgrounds;
const QStringList wwtPlanets = {
"Sun",
"Mercury",
"Venus",
"Earth",
"Moon",
"Mars",
"Jupiter",
"Saturn",
"Uranus",
"Neptune",
"Pluto",
"Io",
"Europa",
"Ganymede",
"Callisto"
static const QStringList wwtPlanets = {
QStringLiteral("Sun"),
QStringLiteral("Mercury"),
QStringLiteral("Venus"),
QStringLiteral("Earth"),
QStringLiteral("Moon"),
QStringLiteral("Mars"),
QStringLiteral("Jupiter"),
QStringLiteral("Saturn"),
QStringLiteral("Uranus"),
QStringLiteral("Neptune"),
QStringLiteral("Pluto"),
QStringLiteral("Io"),
QStringLiteral("Europa"),
QStringLiteral("Ganymede"),
QStringLiteral("Callisto")
};
const QStringList wwtPlanetIDs = {
"Sun",
"Mercury",
"Venus",
"Bing Maps Aerial", //"Earth",
"Moon",
"Visible Imagery", // Mars
"Jupiter",
"Saturn",
"Uranus",
"Neptune",
"Pluto (New Horizons)",
"Io",
"Europa",
"Ganymede",
"Callisto"
static const QStringList wwtPlanetIDs = {
QStringLiteral("Sun"),
QStringLiteral("Mercury"),
QStringLiteral("Venus"),
QStringLiteral("Bing Maps Aerial"), //"Earth",
QStringLiteral("Moon"),
QStringLiteral("Visible Imagery"), // Mars
QStringLiteral("Jupiter"),
QStringLiteral("Saturn"),
QStringLiteral("Uranus"),
QStringLiteral("Neptune"),
QStringLiteral("Pluto (New Horizons)"),
QStringLiteral("Io"),
QStringLiteral("Europa"),
QStringLiteral("Ganymede"),
QStringLiteral("Callisto")
};
// From https://github.com/cds-astro/aladin-lite/blob/master/src/js/ImageLayer.js
const QStringList aladinBackgrounds = {
"DSS colored",
"DSS2 Red (F+R)",
"2MASS colored",
"Density map for Gaia EDR3 (I/350/gaiaedr3)",
"PanSTARRS DR1 g",
"PanSTARRS DR1 color",
"DECaPS DR1 color",
"Fermi color",
"Halpha",
"GALEXGR6_7 NUV",
"IRIS colored",
"Mellinger colored",
"SDSS9 colored",
"SDSS9 band-g",
"IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)",
"VTSS-Ha",
"XMM PN colored",
"AllWISE color",
"GLIMPSE360"
static const QStringList aladinBackgrounds = {
QStringLiteral("DSS colored"),
QStringLiteral("DSS2 Red (F+R)"),
QStringLiteral("2MASS colored"),
QStringLiteral("Density map for Gaia EDR3 (I/350/gaiaedr3)"),
QStringLiteral("PanSTARRS DR1 g"),
QStringLiteral("PanSTARRS DR1 color"),
QStringLiteral("DECaPS DR1 color"),
QStringLiteral("Fermi color"),
QStringLiteral("Halpha"),
QStringLiteral("GALEXGR6_7 NUV"),
QStringLiteral("IRIS colored"),
QStringLiteral("Mellinger colored"),
QStringLiteral("SDSS9 colored"),
QStringLiteral("SDSS9 band-g"),
QStringLiteral("IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)"),
QStringLiteral("VTSS-Ha"),
QStringLiteral("XMM PN colored"),
QStringLiteral("AllWISE color"),
QStringLiteral("GLIMPSE360")
};
const QStringList aladinBackgroundIDs = {
"P/DSS2/color",
"P/DSS2/red",
"P/2MASS/color",
"P/DM/I/350/gaiaedr3",
"P/PanSTARRS/DR1/g",
"P/PanSTARRS/DR1/color-z-zg-g",
"P/DECaPS/DR1/color",
"P/Fermi/color",
"P/Finkbeiner",
"P/GALEXGR6_7/NUV",
"P/IRIS/color",
"P/Mellinger/color",
"P/SDSS9/color",
"P/SDSS9/g",
"P/SPITZER/color",
"P/VTSS/Ha",
"xcatdb/P/XMM/PN/color",
"P/allWISE/color",
"P/GLIMPSE360"
};
const QStringList esaSkyBackgrounds = {
static const QStringList aladinBackgroundIDs = {
QStringLiteral("P/DSS2/color"),
QStringLiteral("P/DSS2/red"),
QStringLiteral("P/2MASS/color"),
QStringLiteral("P/DM/I/350/gaiaedr3"),
QStringLiteral("P/PanSTARRS/DR1/g"),
QStringLiteral("P/PanSTARRS/DR1/color-z-zg-g"),
QStringLiteral("P/DECaPS/DR1/color"),
QStringLiteral("P/Fermi/color"),
QStringLiteral("P/Finkbeiner"),
QStringLiteral("P/GALEXGR6_7/NUV"),
QStringLiteral("P/IRIS/color"),
QStringLiteral("P/Mellinger/color"),
QStringLiteral("P/SDSS9/color"),
QStringLiteral("P/SDSS9/g"),
QStringLiteral("P/SPITZER/color"),
QStringLiteral("P/VTSS/Ha"),
QStringLiteral("xcatdb/P/XMM/PN/color"),
QStringLiteral("P/allWISE/color"),
QStringLiteral("P/GLIMPSE360")
};
QString SkyMapGUI::backgroundID(const QString& name)
@ -906,7 +890,7 @@ void SkyMapGUI::updateBackgrounds()
if (m_settings.m_map == "WWT") {
if (m_settings.m_projection == "Sky") {
backgrounds = wwtBackgrounds;
backgrounds = m_wwtBackgrounds;
} else if (m_settings.m_projection == "Solar system") {
backgrounds = wwtPlanets;
} else {
@ -936,11 +920,11 @@ void SkyMapGUI::updateBackgrounds()
void SkyMapGUI::wtmlUpdated(const QList<WTML::ImageSet>& dataSets)
{
wwtBackgrounds.clear();
m_wwtBackgrounds.clear();
for (int i = 0; i < dataSets.size(); i++)
{
if (dataSets[i].m_dataSetType == "Sky") {
wwtBackgrounds.append(dataSets[i].m_name);
m_wwtBackgrounds.append(dataSets[i].m_name);
}
}
updateBackgrounds();
@ -1027,10 +1011,18 @@ void SkyMapGUI::sendToRotator(const QString& name, double az, double alt)
}
}
void SkyMapGUI::updateSourceList()
void SkyMapGUI::updateSourceList(const QStringList& renameFrom, const QStringList& renameTo)
{
m_availableChannelOrFeatures = MainCore::instance()->getAvailableChannelsAndFeatures(SkyMapSettings::m_pipeURIs);
m_availableChannelOrFeatures = m_availableChannelOrFeatureHandler.getAvailableChannelOrFeatureList();
// Update source settting if it has been renamed
if (renameFrom.contains(m_settings.m_source))
{
m_settings.m_source = renameTo[renameFrom.indexOf(m_settings.m_source)];
applySetting("source"); // Only call after m_availableChannelOrFeatures has been updated
}
int prevIdx = ui->source->currentIndex();
ui->source->blockSignals(true);
ui->source->clear();
@ -1038,89 +1030,37 @@ void SkyMapGUI::updateSourceList()
ui->source->addItem(item.getLongId());
}
// Select current setting, if exists
// If not, make sure nothing selected, as channel may be created later on
// Select current setting, if it exists
// If not, and no prior setting, make sure nothing selected, as channel/feature may be created later on
// If not found and something was previously selected, clear the setting, as probably deleted
int idx = ui->source->findText(m_settings.m_source);
if (idx >= 0)
{
ui->source->setCurrentIndex(idx);
ui->track->setEnabled(true);
}
else
else if (prevIdx == -1)
{
ui->source->setCurrentIndex(-1);
ui->track->setChecked(false);
ui->track->setEnabled(false);
}
else
{
m_settings.m_source = "";
applySetting("source");
}
ui->source->blockSignals(false);
// If no current settting, select first available
if (m_settings.m_source.isEmpty())
if (m_settings.m_source.isEmpty() && (ui->source->count() > 0))
{
ui->source->setCurrentIndex(0);
on_source_currentIndexChanged(0);
}
}
void SkyMapGUI::handleFeatureAdded(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
updateSourceList();
}
void SkyMapGUI::handleFeatureRemoved(int featureSetIndex, Feature *oldFeature)
{
(void) featureSetIndex;
(void) oldFeature;
updateSourceList();
}
void SkyMapGUI::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
(void) deviceSetIndex;
(void) channel;
updateSourceList();
}
void SkyMapGUI::handleChannelRemoved(int deviceSetIndex, ChannelAPI *channel)
{
(void) deviceSetIndex;
(void) channel;
updateSourceList();
}
void SkyMapGUI::registerPipe(QObject *object)
{
qDebug("SkyMapGUI::registerPipe: register %s (%p)", qPrintable(object->objectName()), object);
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(object, this, "target");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handlePipeMessageQueue(messageQueue); },
Qt::QueuedConnection
);
pipe = messagePipes.registerProducerToConsumer(object, this, "skymap.target");
messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handlePipeMessageQueue(messageQueue); },
Qt::QueuedConnection
);
}
void SkyMapGUI::handlePipeMessageQueue(MessageQueue* messageQueue)
{
Message* message;

View File

@ -34,6 +34,7 @@
#include "feature/featuregui.h"
#include "util/messagequeue.h"
#include "settings/rollupstate.h"
#include "availablechannelorfeaturehandler.h"
#include "maincore.h"
#include "skymapsettings.h"
@ -72,10 +73,12 @@ private:
PluginAPI* m_pluginAPI;
FeatureUISet* m_featureUISet;
SkyMapSettings m_settings;
QList<QString> m_settingsKeys;
RollupState m_rollupState;
bool m_doApplySettings;
QList<MainCore::AvailableChannelOrFeature> m_availableChannelOrFeatures;
QObject *m_source;
AvailableChannelOrFeatureList m_availableChannelOrFeatures;
AvailableChannelOrFeatureHandler m_availableChannelOrFeatureHandler;
SkyMap* m_skymap;
MessageQueue m_inputMessageQueue;
@ -90,6 +93,8 @@ private:
double m_dec;
QDateTime m_dateTime; //!< Date time from source plugin
QStringList m_wwtBackgrounds;
explicit SkyMapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
virtual ~SkyMapGUI();
@ -112,8 +117,6 @@ private:
void updateProjection();
void find(const QString& text);
void sendToRotator(const QString& name, double az, double alt);
void updateSourceList();
void registerPipe(QObject *object);
private slots:
void onMenuDialogCalled(const QPoint &p);
@ -140,11 +143,7 @@ private slots:
void preferenceChanged(int elementType);
void receivedEvent(const QJsonObject &obj);
void wtmlUpdated(const QList<WTML::ImageSet>& dataSets);
void handleFeatureAdded(int featureSetIndex, Feature *feature);
void handleFeatureRemoved(int featureSetIndex, Feature *oldFeature);
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleChannelRemoved(int deviceSetIndex, ChannelAPI *channel);
void updateSourceList(const QStringList& renameFrom, const QStringList& renameTo);
void handlePipeMessageQueue(MessageQueue* messageQueue);
};

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
@ -42,7 +42,8 @@
MESSAGE_CLASS_DEFINITION(StarTracker::MsgConfigureStarTracker, Message)
MESSAGE_CLASS_DEFINITION(StarTracker::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(StarTracker::MsgSetSolarFlux, Message)
MESSAGE_CLASS_DEFINITION(StarTracker::MsgReportAvailableSatelliteTrackers, Message)
MESSAGE_CLASS_DEFINITION(StarTracker::MsgRequestAvailableFeatures, Message)
MESSAGE_CLASS_DEFINITION(StarTracker::MsgReportAvailableFeatures, Message)
const char* const StarTracker::m_featureIdURI = "sdrangel.feature.startracker";
const char* const StarTracker::m_featureId = "StarTracker";
@ -50,7 +51,9 @@ const char* const StarTracker::m_featureId = "StarTracker";
StarTracker::StarTracker(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_thread(nullptr),
m_worker(nullptr)
m_worker(nullptr),
m_availableChannelHandler({"sdrangel.channel.radioastronomy"}, QStringList{"startracker.display"}),
m_availableFeatureHandler({"sdrangel.feature.satellitetracker", "sdrangel.feature.skymap"})
{
qDebug("StarTracker::StarTracker: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
@ -70,36 +73,17 @@ StarTracker::StarTracker(WebAPIAdapterInterface *webAPIAdapterInterface) :
m_temps.append(new FITS(":/startracker/startracker/408mhz_ra_dec.fits"));
m_temps.append(new FITS(":/startracker/startracker/1420mhz_ra_dec.fits"));
m_spectralIndex = new FITS(":/startracker/startracker/408mhz_ra_dec_spectral_index.fits");
scanAvailableChannels();
scanAvailableFeatures();
QObject::connect(
MainCore::instance(),
&MainCore::channelAdded,
this,
&StarTracker::handleChannelAdded
);
QObject::connect(
MainCore::instance(),
&MainCore::featureAdded,
this,
&StarTracker::handleFeatureAdded
);
QObject::connect(
MainCore::instance(),
&MainCore::featureRemoved,
this,
&StarTracker::handleFeatureRemoved
);
QObject::connect(&m_availableChannelHandler, &AvailableChannelOrFeatureHandler::messageEnqueued, this, &StarTracker::handleChannelMessageQueue);
m_availableChannelHandler.scanAvailableChannelsAndFeatures();
QObject::connect(&m_availableFeatureHandler, &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged, this, &StarTracker::featuresChanged);
m_availableFeatureHandler.scanAvailableChannelsAndFeatures();
}
StarTracker::~StarTracker()
{
QObject::disconnect(
MainCore::instance(),
&MainCore::channelAdded,
this,
&StarTracker::handleChannelAdded
);
QObject::disconnect(&m_availableChannelHandler, &AvailableChannelOrFeatureHandler::messageEnqueued, this, &StarTracker::handleChannelMessageQueue);
QObject::disconnect(&m_availableFeatureHandler, &AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged, this, &StarTracker::featuresChanged);
QObject::disconnect(
m_networkManager,
&QNetworkAccessManager::finished,
@ -176,6 +160,11 @@ bool StarTracker::handleMessage(const Message& cmd)
return true;
}
else if (MsgRequestAvailableFeatures::match(cmd))
{
notifyUpdateFeatures();
return true;
}
else if (MsgSetSolarFlux::match(cmd))
{
MsgSetSolarFlux& msg = (MsgSetSolarFlux&) cmd;
@ -839,137 +828,18 @@ bool StarTracker::calcSkyTemperature(double frequency, double beamwidth, double
}
}
void StarTracker::scanAvailableChannels()
void StarTracker::featuresChanged()
{
MainCore *mainCore = MainCore::instance();
MessagePipes& messagePipes = mainCore->getMessagePipes();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
m_availableChannels.clear();
for (const auto& deviceSet : deviceSets)
{
DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine;
if (deviceSourceEngine)
{
for (int chi = 0; chi < deviceSet->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = deviceSet->getChannelAt(chi);
if (StarTrackerSettings::m_pipeURIs.contains(channel->getURI()) && !m_availableChannels.contains(channel))
{
qDebug("StarTracker::scanAvailableChannels: register %d:%d %s (%p)",
deviceSet->getIndex(), chi, qPrintable(channel->getURI()), channel);
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channel, this, "startracker.display");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&StarTracker::handleMessagePipeToBeDeleted
);
m_availableChannels.insert(channel);
}
}
}
}
m_availableFeatures = m_availableFeatureHandler.getAvailableChannelOrFeatureList();
notifyUpdateFeatures();
}
void StarTracker::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
qDebug("StarTracker::handleChannelAdded: deviceSetIndex: %d:%d channel: %s (%p)",
deviceSetIndex, channel->getIndexInDeviceSet(), qPrintable(channel->getURI()), channel);
DeviceSet *deviceSet = MainCore::instance()->getDeviceSets()[deviceSetIndex];
DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine;
if (deviceSourceEngine && StarTrackerSettings::m_pipeURIs.contains(channel->getURI()))
{
if (!m_availableChannels.contains(channel))
{
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channel, this, "startracker.display");
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ this->handleChannelMessageQueue(messageQueue); },
Qt::QueuedConnection
);
QObject::connect(
pipe,
&ObjectPipe::toBeDeleted,
this,
&StarTracker::handleMessagePipeToBeDeleted
);
m_availableChannels.insert(channel);
}
}
}
void StarTracker::handleMessagePipeToBeDeleted(int reason, QObject* object)
{
if ((reason == 0) && m_availableChannels.contains((ChannelAPI*) object)) // producer (channel)
{
qDebug("StarTracker::handleMessagePipeToBeDeleted: removing channel at (%p)", object);
m_availableChannels.remove((ChannelAPI*) object);
}
}
void StarTracker::scanAvailableFeatures()
{
qDebug("StarTracker::scanAvailableFeatures");
MainCore *mainCore = MainCore::instance();
std::vector<FeatureSet*>& featureSets = mainCore->getFeatureeSets();
m_satelliteTrackers.clear();
for (const auto& featureSet : featureSets)
{
for (int fei = 0; fei < featureSet->getNumberOfFeatures(); fei++)
{
Feature *feature = featureSet->getFeatureAt(fei);
if ((feature->getURI() == "sdrangel.feature.satellitetracker") || (feature->getURI() == "sdrangel.feature.skymap"))
{
StarTrackerSettings::AvailableFeature satelliteTracker =
StarTrackerSettings::AvailableFeature{featureSet->getIndex(), fei, feature->getIdentifier()};
m_satelliteTrackers[feature] = satelliteTracker;
}
}
}
notifyUpdateSatelliteTrackers();
}
void StarTracker::handleFeatureAdded(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
scanAvailableFeatures();
}
void StarTracker::handleFeatureRemoved(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
scanAvailableFeatures();
}
void StarTracker::notifyUpdateSatelliteTrackers()
void StarTracker::notifyUpdateFeatures()
{
if (getMessageQueueToGUI())
{
MsgReportAvailableSatelliteTrackers *msg = MsgReportAvailableSatelliteTrackers::create();
msg->getFeatures() = m_satelliteTrackers.values();
MsgReportAvailableFeatures *msg = MsgReportAvailableFeatures::create();
msg->getFeatures() = m_availableFeatures;
getMessageQueueToGUI()->push(msg);
}
}

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Kacper Michajłow <kasper93@gmail.com> //
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -22,11 +22,11 @@
#include <QThread>
#include <QNetworkRequest>
#include <QSet>
#include "feature/feature.h"
#include "util/message.h"
#include "util/fits.h"
#include "availablechannelorfeaturehandler.h"
#include "startrackersettings.h"
@ -107,20 +107,34 @@ public:
{ }
};
class MsgReportAvailableSatelliteTrackers : public Message {
class MsgRequestAvailableFeatures : public Message {
MESSAGE_CLASS_DECLARATION
public:
QList<StarTrackerSettings::AvailableFeature>& getFeatures() { return m_availableFeatures; }
static MsgReportAvailableSatelliteTrackers* create() {
return new MsgReportAvailableSatelliteTrackers();
static MsgRequestAvailableFeatures* create() {
return new MsgRequestAvailableFeatures();
}
private:
QList<StarTrackerSettings::AvailableFeature> m_availableFeatures;
MsgRequestAvailableFeatures() :
Message()
{}
};
MsgReportAvailableSatelliteTrackers() :
class MsgReportAvailableFeatures : public Message {
MESSAGE_CLASS_DECLARATION
public:
AvailableChannelOrFeatureList& getFeatures() { return m_availableFeatures; }
static MsgReportAvailableFeatures* create() {
return new MsgReportAvailableFeatures();
}
private:
AvailableChannelOrFeatureList m_availableFeatures;
MsgReportAvailableFeatures() :
Message()
{}
};
@ -183,11 +197,13 @@ private:
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
QSet<ChannelAPI*> m_availableChannels;
QHash<Feature*, StarTrackerSettings::AvailableFeature> m_satelliteTrackers;
Weather *m_weather;
float m_solarFlux;
AvailableChannelOrFeatureHandler m_availableChannelHandler;
AvailableChannelOrFeatureHandler m_availableFeatureHandler;
AvailableChannelOrFeatureList m_availableFeatures;
QList<FITS*> m_temps;
FITS *m_spectralIndex;
@ -197,17 +213,12 @@ private:
void webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const StarTrackerSettings& settings, bool force);
void webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response);
double applyBeam(const FITS *fits, double beamwidth, double ra, double dec, int& imgX, int& imgY) const;
void scanAvailableChannels();
void scanAvailableFeatures();
void notifyUpdateSatelliteTrackers();
void notifyUpdateFeatures();
private slots:
void networkManagerFinished(QNetworkReply *reply);
void weatherUpdated(float temperature, float pressure, float humidity);
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleMessagePipeToBeDeleted(int reason, QObject* object);
void handleFeatureAdded(int featureSetIndex, Feature *feature);
void handleFeatureRemoved(int featureSetIndex, Feature *feature);
void featuresChanged();
void handleChannelMessageQueue(MessageQueue* messageQueue);
};

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021-2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2021-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// //
// This program is free software; you can redistribute it and/or modify //
@ -220,17 +220,17 @@ bool StarTrackerGUI::handleMessage(const Message& message)
}
return true;
}
else if (StarTracker::MsgReportAvailableSatelliteTrackers::match(message))
else if (StarTracker::MsgReportAvailableFeatures::match(message))
{
StarTracker::MsgReportAvailableSatelliteTrackers& report = (StarTracker::MsgReportAvailableSatelliteTrackers&) message;
updateSatelliteTrackerList(report.getFeatures());
StarTracker::MsgReportAvailableFeatures& report = (StarTracker::MsgReportAvailableFeatures&) message;
updateFeatureList(report.getFeatures());
return true;
}
return false;
}
void StarTrackerGUI::updateSatelliteTrackerList(const QList<StarTrackerSettings::AvailableFeature>& satelliteTrackers)
void StarTrackerGUI::updateFeatureList(const AvailableChannelOrFeatureList& features)
{
// Update list of plugins we can get target from
ui->target->blockSignals(true);
@ -242,9 +242,9 @@ void StarTrackerGUI::updateSatelliteTrackerList(const QList<StarTrackerSettings:
bool found = false;
if (text.contains("SatelliteTracker") || text.contains("SkyMap"))
{
for (const auto& satelliteTracker : satelliteTrackers)
for (const auto& feature : features)
{
if (satelliteTracker.getName() == text)
if (feature.getLongId() == text)
{
found = true;
break;
@ -263,9 +263,9 @@ void StarTrackerGUI::updateSatelliteTrackerList(const QList<StarTrackerSettings:
}
// Add new targets
for (const auto& satelliteTracker : satelliteTrackers)
for (const auto& feature : features)
{
QString name = satelliteTracker.getName();
QString name = feature.getLongId();
if (ui->target->findText(name) == -1) {
ui->target->addItem(name);
}
@ -454,6 +454,9 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
createGalacticLineOfSightScene();
plotChart();
StarTracker::MsgRequestAvailableFeatures *message = StarTracker::MsgRequestAvailableFeatures::create();
m_starTracker->getInputMessageQueue()->push(message);
}
StarTrackerGUI::~StarTrackerGUI()

View File

@ -33,6 +33,7 @@
#include "util/fits.h"
#include "gui/httpdownloadmanagergui.h"
#include "settings/rollupstate.h"
#include "availablechannelorfeature.h"
#include "startrackersettings.h"
@ -169,7 +170,7 @@ private:
void updateSolarFlux(bool all);
void makeUIConnections();
void limitAzElRange(double& azimuth, double& elevation) const;
void updateSatelliteTrackerList(const QList<StarTrackerSettings::AvailableFeature>& satelliteTrackers);
void updateFeatureList(const AvailableChannelOrFeatureList& features);
private slots:
void onMenuDialogCalled(const QPoint &p);

View File

@ -23,14 +23,6 @@
#include "startrackersettings.h"
const QStringList StarTrackerSettings::m_pipeTypes = {
QStringLiteral("RadioAstronomy")
};
const QStringList StarTrackerSettings::m_pipeURIs = {
QStringLiteral("sdrangel.channel.radioastronomy")
};
StarTrackerSettings::StarTrackerSettings() :
m_rollupState(nullptr)
{

View File

@ -2,7 +2,7 @@
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020-2021, 2023 Jon Beniston, M7RCE <jon@beniston.com> //
// Copyright (C) 2020-2024 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// 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 //
@ -30,23 +30,6 @@ class Serializable;
struct StarTrackerSettings
{
struct AvailableFeature
{
int m_featureSetIndex;
int m_featureIndex;
QString m_type;
AvailableFeature() = default;
AvailableFeature(const AvailableFeature&) = default;
AvailableFeature& operator=(const AvailableFeature&) = default;
bool operator==(const AvailableFeature& a) const {
return (m_featureSetIndex == a.m_featureSetIndex) && (m_featureIndex == a.m_featureIndex) && (m_type == a.m_type);
}
QString getName() const {
return QString("F%1:%2 %3").arg(m_featureSetIndex).arg(m_featureIndex).arg(m_type);
}
};
QString m_ra;
QString m_dec;
double m_latitude;
@ -102,9 +85,6 @@ struct StarTrackerSettings
void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; }
void applySettings(const QStringList& settingsKeys, const StarTrackerSettings& settings);
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
static const QStringList m_pipeTypes;
static const QStringList m_pipeURIs;
};
#endif // INCLUDE_FEATURE_STARTRACKERSETTINGS_H_

View File

@ -286,6 +286,8 @@ set(sdrbase_SOURCES
websockets/wsspectrum.cpp
availablechannelorfeature.cpp
availablechannelorfeaturehandler.cpp
mainparser.cpp
maincore.cpp
remotetcpsinkstarter.cpp
@ -525,6 +527,8 @@ set(sdrbase_HEADERS
websockets/wsspectrum.h
availablechannelorfeature.h
availablechannelorfeaturehandler.h
mainparser.h
maincore.h
remotetcpsinkstarter.h

View File

@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Jon Beniston <jon@beniston.com> //
// //
// 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 "availablechannelorfeature.h"
#include "feature/feature.h"
#include "channel/channelapi.h"
#include "maincore.h"
int AvailableChannelOrFeatureList::indexOfObject(const QObject *object, int from) const
{
for (int index = from; index < size(); index++)
{
if (at(index).m_object == object) {
return index;
}
}
return -1;
}
int AvailableChannelOrFeatureList::indexOfId(const QString& id, int from) const
{
for (int index = from; index < size(); index++)
{
if (at(index).getId() == id) {
return index;
}
}
return -1;
}
int AvailableChannelOrFeatureList::indexOfLongId(const QString& longId, int from) const
{
for (int index = from; index < size(); index++)
{
if (at(index).getLongId() == longId) {
return index;
}
}
return -1;
}

View File

@ -0,0 +1,77 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Jon Beniston <jon@beniston.com> //
// //
// 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 SDRBASE_AVAILABLECHANNELORFEATURE_H_
#define SDRBASE_AVAILABLECHANNELORFEATURE_H_
#include "pipes/messagepipes.h"
#include "export.h"
struct AvailableChannelOrFeature
{
QChar m_kind; //!< 'R' or 'T' for channel, 'M' for MIMO channel, 'F' for feature as from MainCore::getDeviceSetTypeId
int m_superIndex; //!< Device Set index or Feature Set index
int m_index; //!< Channel or Feature index
int m_streamIndex; //!< For MIMO channels only
QString m_type; //!< Plugin type (E.g. NFMDemod)
QObject *m_object; //!< Pointer to the object (ChannelAPI or Feature object)
AvailableChannelOrFeature() = default;
AvailableChannelOrFeature(const AvailableChannelOrFeature&) = default;
AvailableChannelOrFeature& operator=(const AvailableChannelOrFeature&) = default;
bool operator==(const AvailableChannelOrFeature& a) const {
return (m_kind == a.m_kind) && (m_superIndex == a.m_superIndex) && (m_index == a.m_index) && (m_type == a.m_type) && ((m_kind == 'M') && (m_streamIndex == a.m_streamIndex));
}
QString getId() const { // Eg: "R3:4"
QString id = QString("%1%2:%3").arg(m_kind).arg(m_superIndex).arg(m_index);
if (m_kind == "M") {
id.append(QString(".%1").arg(m_streamIndex));
}
return id;
}
QString getLongId() const { // Eg: "F0:1 StarTracker"
return QString("%1 %2").arg(getId()).arg(m_type);
}
};
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
inline uint qHash(const AvailableChannelOrFeature &c, uint seed = 0) noexcept
{
return qHash(c.getLongId(), seed);
}
#else
size_t qHash(const AvailableChannelOrFeatureList &c, size_t seed = 0) noexcept
{
return qHash(c.getLongId(), seed);
}
#endif
class SDRBASE_API AvailableChannelOrFeatureList : public QList<AvailableChannelOrFeature>
{
public:
AvailableChannelOrFeatureList() {}
inline explicit AvailableChannelOrFeatureList(const AvailableChannelOrFeature &i) { append(i); }
int indexOfObject(const QObject *object, int from=0) const; //!< // Find index of entry containing specified object. -1 if not found.
int indexOfId(const QString& longId, int from=0) const; //!< // Find index of entry with specified Id. -1 if not found.
int indexOfLongId(const QString& longId, int from=0) const; //!< // Find index of entry with specified long Id. -1 if not found.
};
#endif // SDRBASE_AVAILABLECHANNELORFEATURE_H_

View File

@ -0,0 +1,173 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Jon Beniston <jon@beniston.com> //
// //
// 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 "availablechannelorfeaturehandler.h"
#include "feature/feature.h"
#include "channel/channelapi.h"
#include "maincore.h"
void AvailableChannelOrFeatureHandler::init()
{
QObject::connect(MainCore::instance(), &MainCore::channelAdded, this, &AvailableChannelOrFeatureHandler::handleChannelAdded);
QObject::connect(MainCore::instance(), &MainCore::channelRemoved, this, &AvailableChannelOrFeatureHandler::handleChannelRemoved);
QObject::connect(MainCore::instance(), &MainCore::featureAdded, this, &AvailableChannelOrFeatureHandler::handleFeatureAdded);
QObject::connect(MainCore::instance(), &MainCore::featureRemoved, this, &AvailableChannelOrFeatureHandler::handleFeatureRemoved);
// Don't call scanAvailableChannelsAndFeatures() here, as channelsOrFeaturesChanged slot will not yet be connected
// Owner should call scanAvailableChannelsAndFeatures after connection
}
void AvailableChannelOrFeatureHandler::scanAvailableChannelsAndFeatures()
{
// Get current list of channels and features with specified URIs
AvailableChannelOrFeatureList availableChannelOrFeatureList = MainCore::instance()->getAvailableChannelsAndFeatures(m_uris, m_kinds);
// Look for new channels or features
for (const auto& channelOrFeature : availableChannelOrFeatureList)
{
if (!m_availableChannelOrFeatureList.contains(channelOrFeature))
{
// For MIMO channels, get notified when stream index changes
if (channelOrFeature.m_kind == 'M')
{
ChannelAPI *channel = qobject_cast<ChannelAPI *>(channelOrFeature.m_object);
if (channel) {
QObject::connect(channel, &ChannelAPI::streamIndexChanged, this, &AvailableChannelOrFeatureHandler::handleStreamIndexChanged);
}
}
// Register pipes for any new channels or features
for (const auto& pipeName: m_pipeNames) {
registerPipe(pipeName, channelOrFeature.m_object);
}
}
}
// Check to see if list has changed
bool changes = m_availableChannelOrFeatureList != availableChannelOrFeatureList;
// Check to see if anything has been renamed, due to indexes changing after device/channel/feature removal
// or if stream index was changed
QStringList renameFrom;
QStringList renameTo;
for (const auto& channelOrFeature : availableChannelOrFeatureList)
{
int index = m_availableChannelOrFeatureList.indexOfObject(channelOrFeature.m_object);
if (index >= 0)
{
const AvailableChannelOrFeature& oldEntry = m_availableChannelOrFeatureList.at(index);
if ((oldEntry.m_superIndex != channelOrFeature.m_superIndex)
|| (oldEntry.m_index != channelOrFeature.m_index)
|| ((channelOrFeature.m_kind == 'M') && (oldEntry.m_streamIndex != channelOrFeature.m_streamIndex))
)
{
renameFrom.append(oldEntry.getId());
renameTo.append(channelOrFeature.getId());
renameFrom.append(oldEntry.getLongId());
renameTo.append(channelOrFeature.getLongId());
}
}
}
m_availableChannelOrFeatureList = availableChannelOrFeatureList;
// Signal if list has changed
if (changes) {
emit channelsOrFeaturesChanged(renameFrom, renameTo);
}
}
QObject* AvailableChannelOrFeatureHandler::registerPipes(const QString& longIdFrom, QObject* to, const QStringList& pipeNames)
{
int index = m_availableChannelOrFeatureList.indexOfLongId(longIdFrom);
if (index >= 0)
{
QObject *object = m_availableChannelOrFeatureList[index].m_object;
for (const auto& pipeName : pipeNames) {
registerPipe(pipeName, object);
}
return object;
}
else
{
return nullptr;
}
}
void AvailableChannelOrFeatureHandler::deregisterPipes(QObject* from, QObject* to, const QStringList& pipeNames)
{
// Don't dereference 'from' here, as it may have been deleted
if (from)
{
qDebug("AvailableChannelOrFeatureHandler::deregisterPipes: unregister (%p)", from);
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
messagePipes.unregisterProducerToConsumer(from, to, "target");
}
}
void AvailableChannelOrFeatureHandler::registerPipe(const QString& pipeName, QObject *channelOrFeature)
{
qDebug("MessagePipeHandler::registerPipe: register %s (%p)", qPrintable(channelOrFeature->objectName()), channelOrFeature);
MessagePipes& messagePipes = MainCore::instance()->getMessagePipes();
ObjectPipe *pipe = messagePipes.registerProducerToConsumer(channelOrFeature, this, pipeName);
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(pipe->m_element);
QObject::connect(
messageQueue,
&MessageQueue::messageEnqueued,
this,
[=](){ emit messageEnqueued(messageQueue); },
Qt::QueuedConnection
);
}
void AvailableChannelOrFeatureHandler::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel)
{
(void) deviceSetIndex;
(void) channel;
scanAvailableChannelsAndFeatures();
}
void AvailableChannelOrFeatureHandler::handleChannelRemoved(int deviceSetIndex, ChannelAPI *channel)
{
(void) deviceSetIndex;
(void) channel;
scanAvailableChannelsAndFeatures();
}
void AvailableChannelOrFeatureHandler::handleStreamIndexChanged(int streamIndex)
{
(void) streamIndex;
scanAvailableChannelsAndFeatures();
}
void AvailableChannelOrFeatureHandler::handleFeatureAdded(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
scanAvailableChannelsAndFeatures();
}
void AvailableChannelOrFeatureHandler::handleFeatureRemoved(int featureSetIndex, Feature *feature)
{
(void) featureSetIndex;
(void) feature;
scanAvailableChannelsAndFeatures();
}

View File

@ -0,0 +1,86 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2024 Jon Beniston <jon@beniston.com> //
// //
// 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 SDRBASE_AVAILABLECHANNELORFEATUREHANDLER_H_
#define SDRBASE_AVAILABLECHANNELORFEATUREHANDLER_H_
#include "pipes/messagepipes.h"
#include "availablechannelorfeature.h"
#include "export.h"
class ChannelAPI;
class Feature;
// Utility class to help keeping track of list of available channels or features and optionally register pipes to them
class SDRBASE_API AvailableChannelOrFeatureHandler : public QObject
{
Q_OBJECT
public:
// Use this constructor to just keep track of available channels and features with specified URIs and kinds
AvailableChannelOrFeatureHandler(QStringList uris, const QString& kinds = "RTMF") :
m_uris(uris),
m_kinds(kinds)
{
init();
}
// Use this constructor to keep track of available channels and features with specified URIs and kinds and register pipes with the given names to them
AvailableChannelOrFeatureHandler(QStringList uris, QStringList pipeNames, const QString& kinds = "RTMF") :
m_uris(uris),
m_pipeNames(pipeNames),
m_kinds(kinds)
{
init();
}
void scanAvailableChannelsAndFeatures();
const AvailableChannelOrFeatureList& getAvailableChannelOrFeatureList() const {
return m_availableChannelOrFeatureList;
}
QObject* registerPipes(const QString& longIdFrom, QObject* to, const QStringList& pipeNames);
void deregisterPipes(QObject* from, QObject* to, const QStringList& pipeNames);
private:
AvailableChannelOrFeatureList m_availableChannelOrFeatureList;
QStringList m_uris; //!< URIs of channels/features we want to create a list for
QStringList m_pipeNames; //!< List of pipe names to register
QString m_kinds;
void init();
void registerPipe(const QString& pipeName, QObject *channelOrFeature);
private slots:
void handleChannelAdded(int deviceSetIndex, ChannelAPI *channel);
void handleChannelRemoved(int deviceSetIndex, ChannelAPI *channel);
void handleStreamIndexChanged(int streamIndex);
void handleFeatureAdded(int featureSetIndex, Feature *feature);
void handleFeatureRemoved(int featureSetIndex, Feature *feature);
signals:
void channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo); //!< Emitted when list of channels or features has changed
void messageEnqueued(MessageQueue *messageQueue); //!< Emitted when message enqueued to a pipe
};
#endif // SDRBASE_AVAILABLECHANNELORFEATUREHANDLER_H_

View File

@ -436,9 +436,9 @@ void MainCore::updateWakeLock()
}
#endif
QList<MainCore::AvailableChannelOrFeature> MainCore::getAvailableChannels(const QStringList& uris)
AvailableChannelOrFeatureList MainCore::getAvailableChannels(const QStringList& uris)
{
QList<AvailableChannelOrFeature> list;
AvailableChannelOrFeatureList list;
for (const auto deviceSet : m_deviceSets)
{
@ -467,9 +467,9 @@ QList<MainCore::AvailableChannelOrFeature> MainCore::getAvailableChannels(const
return list;
}
QList<MainCore::AvailableChannelOrFeature> MainCore::getAvailableFeatures(const QStringList& uris)
AvailableChannelOrFeatureList MainCore::getAvailableFeatures(const QStringList& uris)
{
QList<AvailableChannelOrFeature> list;
AvailableChannelOrFeatureList list;
std::vector<FeatureSet*>& featureSets = MainCore::instance()->getFeatureeSets();
for (const auto& featureSet : featureSets)
@ -496,37 +496,18 @@ QList<MainCore::AvailableChannelOrFeature> MainCore::getAvailableFeatures(const
return list;
}
QList<MainCore::AvailableChannelOrFeature> MainCore::getAvailableChannelsAndFeatures(const QStringList& uris)
AvailableChannelOrFeatureList MainCore::getAvailableChannelsAndFeatures(const QStringList& uris, const QString& kinds)
{
QList<AvailableChannelOrFeature> list;
AvailableChannelOrFeatureList list;
list.append(getAvailableChannels(uris));
list.append(getAvailableFeatures(uris));
if (kinds != "F") {
list.append(getAvailableChannels(uris));
}
if (kinds.contains("F")) {
list.append(getAvailableFeatures(uris));
}
return list;
}
QObject *MainCore::getAvailableChannelOrFeatureById(const QString& id, const QList<AvailableChannelOrFeature>& list)
{
for (const auto& item : list)
{
if (item.getId() == id) {
return item.m_object;
}
}
return nullptr;
}
QObject *MainCore::getAvailableChannelOrFeatureByLongId(const QString& longId, const QList<AvailableChannelOrFeature>& list)
{
for (const auto& item : list)
{
if (item.getLongId() == longId) {
return item.m_object;
}
}
return nullptr;
}
QChar MainCore::getDeviceSetTypeId(const DeviceSet* deviceSet)

View File

@ -38,6 +38,7 @@
#include "pipes/messagepipes.h"
#include "pipes/datapipes.h"
#include "channel/channelapi.h"
#include "availablechannelorfeature.h"
class DeviceSet;
class FeatureSet;
@ -908,39 +909,10 @@ public:
// Position
const QGeoPositionInfo& getPosition() const;
struct AvailableChannelOrFeature
{
QChar m_kind; //!< 'R' or 'T' for channel, 'M' for MIMO channel, 'F' for feature as from MainCore::getDeviceSetTypeId
int m_superIndex; //!< Device Set index or Feature Set index
int m_index; //!< Channel or Feature index
int m_streamIndex; //!< For MIMO channels only
QString m_type; //!< Plugin type (E.g. NFMDemod)
QObject *m_object; //!< Pointer to the object (ChannelAPI or Feature object)
AvailableChannelOrFeature() = default;
AvailableChannelOrFeature(const AvailableChannelOrFeature&) = default;
AvailableChannelOrFeature& operator=(const AvailableChannelOrFeature&) = default;
bool operator==(const AvailableChannelOrFeature& a) const {
return (m_kind == a.m_kind) && (m_superIndex == a.m_superIndex) && (m_index == a.m_index) && (m_type == a.m_type);
}
QString getId() const { // Eg: "R3:4"
QString id = QString("%1%2:%3").arg(m_kind).arg(m_superIndex).arg(m_index);
if (m_kind == "M") {
id.append(QString(".%1").arg(m_streamIndex));
}
return id;
}
QString getLongId() const { // Eg: "F0:1 StarTracker"
return QString("%1 %2").arg(getId()).arg(m_type);
}
};
// Use QList so ordered numerically
QList<AvailableChannelOrFeature> getAvailableChannels(const QStringList& uris); // Get hash of available channels with given URIs or all if empty list. Hash hey is Id
QList<AvailableChannelOrFeature> getAvailableFeatures(const QStringList& uris); // Get hash of available features with given URIs or all if empty list. Hash key is Id
QList<AvailableChannelOrFeature> getAvailableChannelsAndFeatures(const QStringList& uris); // Get hash of available channels and features with given URIs or all if empty list. Hash key is Id
static QObject *getAvailableChannelOrFeatureById(const QString& id, const QList<AvailableChannelOrFeature>& list);
static QObject *getAvailableChannelOrFeatureByLongId(const QString& longId, const QList<AvailableChannelOrFeature>& list);
// Lists of available channels and features. List should be ordered by indexes. Plugins should use AvailableChannelOrFeatureHandler to maintain this list
AvailableChannelOrFeatureList getAvailableChannels(const QStringList& uris); // Get list of available channels with given URIs or all if empty list.
AvailableChannelOrFeatureList getAvailableFeatures(const QStringList& uris); // Get list of available features with given URIs or all if empty list.
AvailableChannelOrFeatureList getAvailableChannelsAndFeatures(const QStringList& uris, const QString& kinds); // Get list of available channels and features with given URIs or all if empty list.
// Ids
QChar getDeviceSetTypeId(const DeviceSet* deviceSet); //!< Get Type Id (E.g. 'R', 'T' or 'M') for the given device set