From 0ab857c358035b1721875a8df6b036f6cef02dad Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Wed, 13 Jan 2021 17:07:38 +0000 Subject: [PATCH] Add PipeEndPoint class, that both ChannelAPI and Feature can inherit from, to allow either to be used as pipe sources. Add MsgMapItem, MsgPacket and MsgTargetAzimuthElevation messages that can be passed between channels and features via pipes. --- plugins/feature/vorlocalizer/vorlocalizer.cpp | 4 +- sdrbase/CMakeLists.txt | 2 + sdrbase/channel/channelapi.cpp | 1 + sdrbase/channel/channelapi.h | 3 +- sdrbase/feature/feature.cpp | 13 ++ sdrbase/feature/feature.h | 5 +- sdrbase/maincore.cpp | 3 + sdrbase/maincore.h | 87 ++++++++++- sdrbase/pipes/messagepipes.cpp | 7 +- sdrbase/pipes/messagepipes.h | 10 +- sdrbase/pipes/messagepipescommon.h | 4 +- sdrbase/pipes/messagepipesgcworker.cpp | 9 +- sdrbase/pipes/messagepipesgcworker.h | 4 +- sdrbase/pipes/pipeendpoint.cpp | 147 ++++++++++++++++++ sdrbase/pipes/pipeendpoint.h | 100 ++++++++++++ 15 files changed, 380 insertions(+), 19 deletions(-) create mode 100644 sdrbase/pipes/pipeendpoint.cpp create mode 100644 sdrbase/pipes/pipeendpoint.h diff --git a/plugins/feature/vorlocalizer/vorlocalizer.cpp b/plugins/feature/vorlocalizer/vorlocalizer.cpp index 220b5d7b7..a01a0cc82 100644 --- a/plugins/feature/vorlocalizer/vorlocalizer.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizer.cpp @@ -244,8 +244,8 @@ bool VORLocalizer::handleMessage(const Message& cmd) qDebug() << "VORLocalizer::handleMessage: MsgReportChannelDeleted"; MessagePipesCommon::MsgReportChannelDeleted& report = (MessagePipesCommon::MsgReportChannelDeleted&) cmd; const MessagePipesCommon::ChannelRegistrationKey& channelKey = report.getChannelRegistrationKey(); - const ChannelAPI *channel = channelKey.m_key; - m_availableChannels.remove(const_cast(channel)); + const PipeEndPoint *channel = channelKey.m_key; + m_availableChannels.remove(const_cast(reinterpret_cast(channel))); updateChannels(); MessageQueue *messageQueue = MainCore::instance()->getMessagePipes().unregisterChannelToFeature(channel, this, "report"); disconnect(messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleChannelMessageQueue(MessageQueue*))); diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 1b163b135..87ba1431b 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -167,6 +167,7 @@ set(sdrbase_SOURCES pipes/messagepipes.cpp pipes/messagepipescommon.cpp pipes/messagepipesgcworker.cpp + pipes/pipeendpoint.cpp settings/featuresetpreset.cpp settings/preferences.cpp @@ -349,6 +350,7 @@ set(sdrbase_HEADERS pipes/messagepipes.h pipes/messagepipescommon.h pipes/messagepipesgcworker.h + pipes/pipeendpoint.h plugin/plugininterface.h plugin/pluginapi.h diff --git a/sdrbase/channel/channelapi.cpp b/sdrbase/channel/channelapi.cpp index 92fcccd1e..b16f8b4e1 100644 --- a/sdrbase/channel/channelapi.cpp +++ b/sdrbase/channel/channelapi.cpp @@ -19,6 +19,7 @@ #include "util/uid.h" #include "channelapi.h" +#include "maincore.h" ChannelAPI::ChannelAPI(const QString& uri, StreamType streamType) : m_streamType(streamType), diff --git a/sdrbase/channel/channelapi.h b/sdrbase/channel/channelapi.h index 6be93b38a..c9b984211 100644 --- a/sdrbase/channel/channelapi.h +++ b/sdrbase/channel/channelapi.h @@ -27,6 +27,7 @@ #include #include "export.h" +#include "pipes/pipeendpoint.h" class DeviceAPI; @@ -37,7 +38,7 @@ namespace SWGSDRangel class SWGChannelActions; } -class SDRBASE_API ChannelAPI { +class SDRBASE_API ChannelAPI : public PipeEndPoint { public: enum StreamType //!< This is the same enum as in PluginInterface { diff --git a/sdrbase/feature/feature.cpp b/sdrbase/feature/feature.cpp index 1e4940c32..51048ac4a 100644 --- a/sdrbase/feature/feature.cpp +++ b/sdrbase/feature/feature.cpp @@ -23,6 +23,7 @@ #include "SWGDeviceState.h" #include "feature.h" +#include "maincore.h" Feature::Feature(const QString& uri, WebAPIAdapterInterface *webAPIAdapterInterface) : m_webAPIAdapterInterface(webAPIAdapterInterface), @@ -45,6 +46,18 @@ void Feature::handleInputMessages() } } +void Feature::handlePipeMessageQueue(MessageQueue* messageQueue) +{ + Message* message; + + while ((message = messageQueue->pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + int Feature::webapiRunGet( SWGSDRangel::SWGDeviceState& response, QString& errorMessage) const diff --git a/sdrbase/feature/feature.h b/sdrbase/feature/feature.h index 372419e21..aeac7a18f 100644 --- a/sdrbase/feature/feature.h +++ b/sdrbase/feature/feature.h @@ -25,6 +25,7 @@ #include #include "export.h" +#include "pipes/pipeendpoint.h" #include "util/messagequeue.h" class WebAPIAdapterInterface; @@ -40,7 +41,7 @@ namespace SWGSDRangel class SWGChannelSettings; } -class SDRBASE_API Feature : public QObject { +class SDRBASE_API Feature : public QObject, public PipeEndPoint { Q_OBJECT public: enum FeatureState { @@ -155,6 +156,8 @@ protected: protected slots: void handleInputMessages(); + void handlePipeMessageQueue(MessageQueue* messageQueue); + friend PipeEndPoint; private: QString m_name; //!< Unique identifier in a device set used for sorting may change depending on relative position in device set diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index 87cec9ae3..c84adfc0c 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -48,6 +48,9 @@ MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteFeature, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelReport, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelSettings, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelDemodReport, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgMapItem, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgPacket, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgTargetAzimuthElevation, Message) MainCore::MainCore() { diff --git a/sdrbase/maincore.h b/sdrbase/maincore.h index be6119abf..1de9ecd46 100644 --- a/sdrbase/maincore.h +++ b/sdrbase/maincore.h @@ -28,10 +28,10 @@ #include "util/message.h" #include "pipes/messagepipes.h" #include "pipes/datapipes.h" +#include "channel/channelapi.h" class DeviceSet; class FeatureSet; -class ChannelAPI; class Feature; class PluginManager; class MessageQueue; @@ -44,6 +44,8 @@ namespace SWGSDRangel { class SWGChannelReport; class SWGChannelSettings; + class SWGMapItem; + class SWGTargetAzimuthElevation; } class SDRBASE_API MainCore @@ -498,6 +500,89 @@ public: { } }; + // Message to Map feature to display an item on the map + class SDRBASE_API MsgMapItem : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PipeEndPoint *getPipeSource() const { return m_pipeSource; } + SWGSDRangel::SWGMapItem *getSWGMapItem() const { return m_swgMapItem; } + + static MsgMapItem* create(const PipeEndPoint *pipeSource, SWGSDRangel::SWGMapItem *swgMapItem) + { + return new MsgMapItem(pipeSource, swgMapItem); + } + + private: + const PipeEndPoint *m_pipeSource; + SWGSDRangel::SWGMapItem *m_swgMapItem; + + MsgMapItem(const PipeEndPoint *pipeSource, SWGSDRangel::SWGMapItem *swgMapItem) : + Message(), + m_pipeSource(pipeSource), + m_swgMapItem(swgMapItem) + { } + }; + + // Message to pass received packets between channels and features + class SDRBASE_API MsgPacket : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PipeEndPoint *getPipeSource() const { return m_pipeSource; } + QByteArray getPacket() const { return m_packet; } + QDateTime getDateTime() const { return m_dateTime; } + + static MsgPacket* create(const PipeEndPoint *pipeSource, QByteArray packet) + { + return new MsgPacket(pipeSource, packet, QDateTime::currentDateTime()); + } + + static MsgPacket* create(const PipeEndPoint *pipeSource, QByteArray packet, QDateTime dateTime) + { + return new MsgPacket(pipeSource, packet, dateTime); + } + + private: + const PipeEndPoint *m_pipeSource; + QByteArray m_packet; + QDateTime m_dateTime; + + MsgPacket(const PipeEndPoint *pipeSource, QByteArray packet, QDateTime dateTime) : + Message(), + m_pipeSource(pipeSource), + m_packet(packet), + m_dateTime(dateTime) + { + } + }; + + // Message to pass target azimuth and elevation between channels & features + class SDRBASE_API MsgTargetAzimuthElevation : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PipeEndPoint *getPipeSource() const { return m_pipeSource; } + SWGSDRangel::SWGTargetAzimuthElevation *getSWGTargetAzimuthElevation() const { return m_swgTargetAzimuthElevation; } + + static MsgTargetAzimuthElevation* create(const PipeEndPoint *pipeSource, SWGSDRangel::SWGTargetAzimuthElevation *swgTargetAzimuthElevation) + { + return new MsgTargetAzimuthElevation(pipeSource, swgTargetAzimuthElevation); + } + + private: + const PipeEndPoint *m_pipeSource; + SWGSDRangel::SWGTargetAzimuthElevation *m_swgTargetAzimuthElevation; + + MsgTargetAzimuthElevation(const PipeEndPoint *pipeSource, SWGSDRangel::SWGTargetAzimuthElevation *swgTargetAzimuthElevation) : + Message(), + m_pipeSource(pipeSource), + m_swgTargetAzimuthElevation(swgTargetAzimuthElevation) + { } + }; + + + MainCore(); ~MainCore(); static MainCore *instance(); diff --git a/sdrbase/pipes/messagepipes.cpp b/sdrbase/pipes/messagepipes.cpp index 9f997d5da..7977bd011 100644 --- a/sdrbase/pipes/messagepipes.cpp +++ b/sdrbase/pipes/messagepipes.cpp @@ -21,6 +21,7 @@ #include "messagepipesgcworker.h" #include "messagepipes.h" +#include "pipeendpoint.h" MessagePipes::MessagePipes() { @@ -41,19 +42,19 @@ MessagePipes::~MessagePipes() } } -MessageQueue *MessagePipes::registerChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type) +MessageQueue *MessagePipes::registerChannelToFeature(const PipeEndPoint *source, Feature *feature, const QString& type) { return m_registrations.registerProducerToConsumer(source, feature, type); } -MessageQueue *MessagePipes::unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type) +MessageQueue *MessagePipes::unregisterChannelToFeature(const PipeEndPoint *source, Feature *feature, const QString& type) { MessageQueue *messageQueue = m_registrations.unregisterProducerToConsumer(source, feature, type); m_gcWorker->addMessageQueueToDelete(messageQueue); return messageQueue; } -QList* MessagePipes::getMessageQueues(const ChannelAPI *source, const QString& type) +QList* MessagePipes::getMessageQueues(const PipeEndPoint *source, const QString& type) { return m_registrations.getElements(source, type); } diff --git a/sdrbase/pipes/messagepipes.h b/sdrbase/pipes/messagepipes.h index 7b66f945d..0848adc13 100644 --- a/sdrbase/pipes/messagepipes.h +++ b/sdrbase/pipes/messagepipes.h @@ -29,7 +29,7 @@ #include "messagepipescommon.h" #include "elementpipesregistrations.h" -class ChannelAPI; +class PipeEndPoint; class Feature; class MessagePipesGCWorker; class MessageQueue; @@ -43,12 +43,12 @@ public: MessagePipes& operator=(const MessagePipes&) = delete; ~MessagePipes(); - MessageQueue *registerChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); - MessageQueue *unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); - QList* getMessageQueues(const ChannelAPI *source, const QString& type); + MessageQueue *registerChannelToFeature(const PipeEndPoint *source, Feature *feature, const QString& type); + MessageQueue *unregisterChannelToFeature(const PipeEndPoint *source, Feature *feature, const QString& type); + QList* getMessageQueues(const PipeEndPoint *source, const QString& type); private: - ElementPipesRegistrations m_registrations; + ElementPipesRegistrations m_registrations; QThread m_gcThread; //!< Garbage collector thread MessagePipesGCWorker *m_gcWorker; //!< Garbage collector diff --git a/sdrbase/pipes/messagepipescommon.h b/sdrbase/pipes/messagepipescommon.h index d51b05e50..42e7dbb2c 100644 --- a/sdrbase/pipes/messagepipescommon.h +++ b/sdrbase/pipes/messagepipescommon.h @@ -26,14 +26,14 @@ #include "util/message.h" #include "elementpipescommon.h" -class ChannelAPI; +class PipeEndPoint; class Feature; class MessageQueue; class SDRBASE_API MessagePipesCommon { public: - typedef ElementPipesCommon::RegistrationKey ChannelRegistrationKey; + typedef ElementPipesCommon::RegistrationKey ChannelRegistrationKey; /** Send this message to stakeholders when the garbage collector finds that a channel was deleted */ class SDRBASE_API MsgReportChannelDeleted : public Message { diff --git a/sdrbase/pipes/messagepipesgcworker.cpp b/sdrbase/pipes/messagepipesgcworker.cpp index 53b877022..572da409c 100644 --- a/sdrbase/pipes/messagepipesgcworker.cpp +++ b/sdrbase/pipes/messagepipesgcworker.cpp @@ -15,15 +15,20 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include "channel/channelapi.h" #include "feature/feature.h" #include "util/messagequeue.h" #include "maincore.h" #include "messagepipescommon.h" #include "messagepipesgcworker.h" -bool MessagePipesGCWorker::MessagePipesGC::existsProducer(const ChannelAPI *channel) +bool MessagePipesGCWorker::MessagePipesGC::existsProducer(const PipeEndPoint *pipeEndPoint) { - return MainCore::instance()->existsChannel(channel); + // Not overly sure about casting to both types here, but currently safeish as the + // existing functions only use the pointer address - and I presume these + // may be pointers to deleted objects anyway? + return MainCore::instance()->existsChannel((const ChannelAPI *)pipeEndPoint) + || MainCore::instance()->existsFeature((const Feature *)pipeEndPoint); } bool MessagePipesGCWorker::MessagePipesGC::existsConsumer(const Feature *feature) diff --git a/sdrbase/pipes/messagepipesgcworker.h b/sdrbase/pipes/messagepipesgcworker.h index 0af0ecfde..5b9ce1543 100644 --- a/sdrbase/pipes/messagepipesgcworker.h +++ b/sdrbase/pipes/messagepipesgcworker.h @@ -50,10 +50,10 @@ public: bool isRunning() const { return m_running; } private: - class MessagePipesGC : public ElementPipesGC + class MessagePipesGC : public ElementPipesGC { private: - virtual bool existsProducer(const ChannelAPI *channelAPI); + virtual bool existsProducer(const PipeEndPoint *pipeEndPoint); virtual bool existsConsumer(const Feature *feature); virtual void sendMessageToConsumer(const MessageQueue *messageQueue, MessagePipesCommon::ChannelRegistrationKey key, Feature *feature); }; diff --git a/sdrbase/pipes/pipeendpoint.cpp b/sdrbase/pipes/pipeendpoint.cpp new file mode 100644 index 000000000..bf5ed4f2b --- /dev/null +++ b/sdrbase/pipes/pipeendpoint.cpp @@ -0,0 +1,147 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2021 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 // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +#include "dsp/dspengine.h" +#include "device/deviceset.h" +#include "channel/channelapi.h" +#include "feature/featureset.h" +#include "feature/feature.h" +#include "maincore.h" + +#include "pipeendpoint.h" + +MESSAGE_CLASS_DEFINITION(PipeEndPoint::MsgReportPipes, Message) + +QList PipeEndPoint::updateAvailablePipeSources(QString pipeName, QStringList pipeTypes, QStringList pipeURIs, Feature *destinationFeature) +{ + MainCore *mainCore = MainCore::instance(); + MessagePipes& messagePipes = mainCore->getMessagePipes(); + std::vector& deviceSets = mainCore->getDeviceSets(); + QHash availablePipes; + + int deviceIndex = 0; + for (std::vector::const_iterator it = deviceSets.begin(); it != deviceSets.end(); ++it, deviceIndex++) + { + DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine; + DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine; + + if (deviceSourceEngine || deviceSinkEngine) + { + for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++) + { + ChannelAPI *channel = (*it)->getChannelAt(chi); + int i = pipeURIs.indexOf(channel->getURI()); + + if (i >= 0) + { + if (!availablePipes.contains(channel)) + { + MessageQueue *messageQueue = messagePipes.registerChannelToFeature(channel, destinationFeature, pipeName); + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + destinationFeature, + [=](){ destinationFeature->handlePipeMessageQueue(messageQueue); }, + Qt::QueuedConnection + ); + } + + AvailablePipeSource availablePipe = + AvailablePipeSource{ + deviceSinkEngine != nullptr ? AvailablePipeSource::TX : AvailablePipeSource::RX, + deviceIndex, + chi, + channel, + pipeTypes.at(i) + }; + availablePipes[channel] = availablePipe; + } + } + } + } + + std::vector& featureSets = mainCore->getFeatureeSets(); + int featureIndex = 0; + for (std::vector::const_iterator it = featureSets.begin(); it != featureSets.end(); ++it, featureIndex++) + { + for (int fi = 0; fi < (*it)->getNumberOfFeatures(); fi++) + { + Feature *feature = (*it)->getFeatureAt(fi); + int i = pipeURIs.indexOf(feature->getURI()); + + if (i >= 0) + { + if (!availablePipes.contains(feature)) + { + MessageQueue *messageQueue = messagePipes.registerChannelToFeature(feature, destinationFeature, pipeName); + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + destinationFeature, + [=](){ destinationFeature->handlePipeMessageQueue(messageQueue); }, + Qt::QueuedConnection + ); + } + + AvailablePipeSource availablePipe = + AvailablePipeSource{ + AvailablePipeSource::Feature, + featureIndex, + fi, + feature, + pipeTypes.at(i) + }; + availablePipes[feature] = availablePipe; + } + } + } + + QList availablePipeList; + QHash::iterator it = availablePipes.begin(); + + for (; it != availablePipes.end(); ++it) { + availablePipeList.push_back(*it); + } + return availablePipeList; +} + +PipeEndPoint *PipeEndPoint::getPipeEndPoint(const QString name, const QList &availablePipeSources) +{ + QRegExp re("([TRF])([0-9]+):([0-9]+) ([a-zA-Z0-9]+)"); + if (re.exactMatch(name)) + { + QString type = re.capturedTexts()[1]; + int setIndex = re.capturedTexts()[2].toInt(); + int index = re.capturedTexts()[3].toInt(); + QString id = re.capturedTexts()[4]; + + QListIterator itr(availablePipeSources); + while (itr.hasNext()) { + AvailablePipeSource p = itr.next(); + if ((p.m_setIndex == setIndex) && (p.m_index == index) && (id == p.m_id)) + return p.m_source; + } + } + else + qDebug() << "PipeEndPoint::getPipeEndPoint: " << name << " is malformed"; + return nullptr; +} diff --git a/sdrbase/pipes/pipeendpoint.h b/sdrbase/pipes/pipeendpoint.h new file mode 100644 index 000000000..df510f3c4 --- /dev/null +++ b/sdrbase/pipes/pipeendpoint.h @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2021 Jon Beniston, M7RCE // +// // +// Parent for ChannelAPI and Features, where either can be used. // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_PIPES_PIPEENDPOINT_H_ +#define SDRBASE_PIPES_PIPEENDPOINT_H_ + +#include +#include +#include + +#include "util/message.h" +#include "export.h" + +class Feature; + +class SDRBASE_API PipeEndPoint { +public: + + // Used by pipe sinks (features) to record details about available pipe sources (channels or features) + struct AvailablePipeSource + { + enum {RX, TX, Feature} m_type; + int m_setIndex; + int m_index; + PipeEndPoint *m_source; + QString m_id; + + AvailablePipeSource() = default; + AvailablePipeSource(const AvailablePipeSource&) = default; + AvailablePipeSource& operator=(const AvailablePipeSource&) = default; + friend bool operator==(const AvailablePipeSource &lhs, const AvailablePipeSource &rhs) + { + return (lhs.m_type == rhs.m_type) + && (lhs.m_setIndex == rhs.m_setIndex) + && (lhs.m_source == rhs.m_source) + && (lhs.m_id == rhs.m_id); + } + + QString getTypeName() const + { + QStringList typeNames = {"R", "T", "F"}; + return typeNames[m_type]; + } + + // Name for use in GUI combo boxes and WebAPI + QString getName() const + { + QString type; + + return QString("%1%2:%3 %4").arg(getTypeName()) + .arg(m_setIndex) + .arg(m_index) + .arg(m_id); + } + }; + + class SDRBASE_API MsgReportPipes : public Message { + MESSAGE_CLASS_DECLARATION + + public: + QList& getAvailablePipes() { return m_availablePipes; } + + static MsgReportPipes* create() { + return new MsgReportPipes(); + } + + private: + QList m_availablePipes; + + MsgReportPipes() : + Message() + {} + }; + + +protected: + + // Utility functions for pipe sinks to manage list of sources + QList updateAvailablePipeSources(QString pipeName, QStringList pipeTypes, QStringList pipeURIs, Feature *destinationFeature); + PipeEndPoint *getPipeEndPoint(const QString name, const QList &availablePipeSources); + +}; + +#endif // SDRBASE_PIPES_PIPEENDPOINT_H_