diff --git a/src/shared/Components/FilterSelector/FilterSelector.cpp b/src/shared/Components/FilterSelector/FilterSelector.cpp index ef6b251167cd0d6bf6b4db4aa41a495309193404..ec73abd1e7257ff55903421a5af72147c66288d6 100644 --- a/src/shared/Components/FilterSelector/FilterSelector.cpp +++ b/src/shared/Components/FilterSelector/FilterSelector.cpp @@ -20,7 +20,10 @@ #include <Modules/Mavlink/MavlinkVersionHeader.h> #include <Modules/SkywardHubStrings.h> +#include <qglobal.h> +#include <qregularexpression.h> +#include <QDebug> #include <QLabel> #include <QPushButton> @@ -31,11 +34,20 @@ void FilterSelector::setupUi() QVBoxLayout *layout = new QVBoxLayout; - topic = new QComboBox; - topic->setSizeAdjustPolicy(QComboBox::AdjustToContents); - topic->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - topic->addItems(messages.keys()); - layout->addWidget(topic); + systemsComboBox = new QComboBox; + systemsComboBox->setSizePolicy( + QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + systemsComboBox->addItem("Main"); + systemsComboBox->addItem("Payload"); + systemsComboBox->addItem("Rig"); + systemsComboBox->addItem("Gs Receiver"); + layout->addWidget(systemsComboBox); + + messagesComboBox = new QComboBox; + messagesComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + messagesComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + messagesComboBox->addItems(messages.keys()); + layout->addWidget(messagesComboBox); fieldsWidget = new QListWidget; layout->addWidget(fieldsWidget); @@ -47,15 +59,30 @@ void FilterSelector::setupUi() buttons->addWidget(select); layout->addLayout(buttons); - // Set default message + // If the filter is not empty, parse the filter and set system and message if (filter.getTopic().toString() != Topic().toString()) - currentMessage = filter.getTopic().toString(); + { + QRegularExpression filterPattern("^((?:\\w|_)+)/In/((?:\\w|_)+)"); + auto match = filterPattern.match(filter.getTopic().toString()); + + if (match.hasMatch()) + { + auto system = match.captured(1); + currentMessage = match.captured(2); + + systemsComboBox->setCurrentText(system); + } + } else + { currentMessage = messages.keys().at(0); - topic->setCurrentText(currentMessage); + } + messagesComboBox->setCurrentText(currentMessage); + + // Update the fields list with the current selected message setTopic(currentMessage); - connect(topic, &QComboBox::currentTextChanged, this, + connect(messagesComboBox, &QComboBox::currentTextChanged, this, [=](QString key) { if (messages.contains(key)) @@ -120,7 +147,7 @@ void FilterSelector::parseMessagesList() fields.append(SkywardHubStrings::mavlink_component_id_name); fields.append(SkywardHubStrings::mavlink_system_id_name); - messages[QString("Mav/") + messagesList[i].name] = fields; + messages[messagesList[i].name] = fields; } } } @@ -149,7 +176,10 @@ void FilterSelector::setTopic(QString topic) Filter FilterSelector::getFilter() { - auto filter = Filter(Topic(topic->currentText())); + auto targetSystem = systemsComboBox->currentText(); + auto messageName = messagesComboBox->currentText(); + + auto filter = Filter(Topic(targetSystem + "/In/" + messageName)); for (int i = 0; i < fieldsWidget->count(); i++) { @@ -159,4 +189,4 @@ Filter FilterSelector::getFilter() } return filter; -} \ No newline at end of file +} diff --git a/src/shared/Components/FilterSelector/FilterSelector.h b/src/shared/Components/FilterSelector/FilterSelector.h index 63a656e602beb569623b81ebe1cb0be3909a92cb..e69fcb9b7a121a93c92f083864565a8f1a2487c4 100644 --- a/src/shared/Components/FilterSelector/FilterSelector.h +++ b/src/shared/Components/FilterSelector/FilterSelector.h @@ -49,10 +49,11 @@ private: Filter filter; - QString currentMessage; + QComboBox* systemsComboBox; + QComboBox* messagesComboBox; QListWidget* fieldsWidget; - QComboBox* topic; + QString currentMessage; QMap<QString, QList<QString>> messages; signals: diff --git a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp index f5479bbf328196979f47011de871ad0a11734a85..a8fc3dab08c092535ffe562d7c4a43de6163b635 100644 --- a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp +++ b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp @@ -24,7 +24,6 @@ #include <QDebug> #include <QListWidget> #include <QPushButton> -#include <functional> using namespace std; diff --git a/src/shared/Core/MessageBroker/MessageBroker.cpp b/src/shared/Core/MessageBroker/MessageBroker.cpp index ba9f82bf411c7562e71621e6b7057eb6604785f1..d575b5d9e55761e248e789ea4e094904857bf97d 100644 --- a/src/shared/Core/MessageBroker/MessageBroker.cpp +++ b/src/shared/Core/MessageBroker/MessageBroker.cpp @@ -19,6 +19,7 @@ #include "MessageBroker.h" #include <Modules/Module.h> +#include <qglobal.h> MessageBroker& MessageBroker::getInstance() { @@ -50,6 +51,9 @@ void MessageBroker::unsubscribe(Filter filter, Module* module) void MessageBroker::publish(const Message& message) { + qDebug() << "Publishing message: " << message.getTopic().toString() << " - " + << message.toString(); + // Iterate over all filters to check if the message matches any for (auto filter : observers.uniqueKeys()) { diff --git a/src/shared/Modules/CommandPad/CommandPad.cpp b/src/shared/Modules/CommandPad/CommandPad.cpp index 85e8d638f169e68e0b491fab7a1cc461682b4bd5..6fae95cc943eef102c07f7b3ab08f0ce8776b4fa 100644 --- a/src/shared/Modules/CommandPad/CommandPad.cpp +++ b/src/shared/Modules/CommandPad/CommandPad.cpp @@ -19,6 +19,7 @@ #include "CommandPad.h" #include <Modules/CommandPad/MessagesList.h> +#include <Modules/Mavlink/MavlinkCodec.h> #include <QVBoxLayout> @@ -26,7 +27,6 @@ CommandPad::CommandPad() : Module(ModuleId::COMMAND_PAD) { setupUi(); } CommandPad::~CommandPad() { - delete messagesListComboBox; for (auto key : formElements.keys()) delete formElements[key]; } @@ -35,6 +35,8 @@ XmlObject CommandPad::toXmlObject() { XmlObject obj = Module::toXmlObject(); + obj.addAttribute("target_system", systemsComboBox->currentText()); + auto key = messagesListComboBox->currentText(); if (formElements.contains(key)) { @@ -49,6 +51,13 @@ void CommandPad::fromXmlObject(const XmlObject &obj) { auto key = obj.getAttribute("message_id"); + auto targetSystem = obj.getAttribute("target_system"); + auto index = systemsComboBox->findText(targetSystem); + if (index >= 0) + { + systemsComboBox->setCurrentIndex(index); + } + if (formElements.contains(key)) { formElements[key]->fromXmlObject(obj); @@ -61,6 +70,15 @@ void CommandPad::setupUi() QVBoxLayout *outerLayout = new QVBoxLayout; outerLayout->addStretch(); + systemsComboBox = new QComboBox; + systemsComboBox->setSizePolicy( + QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + systemsComboBox->addItem("Main", MavlinkCodec::SysIdMain); + systemsComboBox->addItem("Payload", MavlinkCodec::SysIdPayload); + systemsComboBox->addItem("Rig", MavlinkCodec::SysIdRig); + systemsComboBox->addItem("Gs Receiver", MavlinkCodec::SysIdGsReceiver); + outerLayout->addWidget(systemsComboBox); + messagesListComboBox = new QComboBox; messagesListComboBox->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); @@ -99,7 +117,8 @@ void CommandPad::setupUi() auto key = messagesListComboBox->currentText(); if (formElements.contains(key)) { - auto message = formElements[key]->prepareMessage(key); + auto message = formElements[key]->prepareMessage( + systemsComboBox->currentText(), key); MessageBroker::getInstance().publish(message); } }); diff --git a/src/shared/Modules/CommandPad/CommandPad.h b/src/shared/Modules/CommandPad/CommandPad.h index ec9e24502a53ec03a257cc196970ab4a9ec8c515..ada4d43592dbb1cb10011541450a75590533ccda 100644 --- a/src/shared/Modules/CommandPad/CommandPad.h +++ b/src/shared/Modules/CommandPad/CommandPad.h @@ -38,6 +38,7 @@ private: void setupUi(); QString currentMessage; + QComboBox* systemsComboBox; QComboBox* messagesListComboBox; QMap<QString, MessageFormElement*> formElements; }; diff --git a/src/shared/Modules/CommandPad/MessageFormElement.cpp b/src/shared/Modules/CommandPad/MessageFormElement.cpp index d34e6c1b10d4811f00c1a3afdaeaa66e47b5650f..a725caa95fceab599282c5161c680e4eb52f8b0a 100644 --- a/src/shared/Modules/CommandPad/MessageFormElement.cpp +++ b/src/shared/Modules/CommandPad/MessageFormElement.cpp @@ -259,9 +259,10 @@ void MessageFormElement::removeFromGridLayout(QGridLayout* layout) } } -Message MessageFormElement::prepareMessage(const QString& messageId) +Message MessageFormElement::prepareMessage(const QString& sysName, + const QString& messageId) { - Message message(Topic{SkywardHubStrings::commandsTopic + "/" + messageId}); + Message message(Topic{sysName + "/Out/" + messageId}); for (auto key : comboBoxMap.keys()) { @@ -285,4 +286,4 @@ Message MessageFormElement::prepareMessage(const QString& messageId) } return message; -} \ No newline at end of file +} diff --git a/src/shared/Modules/CommandPad/MessageFormElement.h b/src/shared/Modules/CommandPad/MessageFormElement.h index 7c85e7471840e672fd159ea479cf1ba22bfce508..609349a4d36e234cc2b43b02a887ae36e6f9bdff 100644 --- a/src/shared/Modules/CommandPad/MessageFormElement.h +++ b/src/shared/Modules/CommandPad/MessageFormElement.h @@ -70,7 +70,7 @@ public: void removeFromGridLayout(QGridLayout* layout); - Message prepareMessage(const QString& messageId); + Message prepareMessage(const QString& sysName, const QString& messageId); private: QMap<QString, QPair<QLabel*, QComboBox*>> comboBoxMap; diff --git a/src/shared/Modules/CompactCommandPad/CommandSelector.cpp b/src/shared/Modules/CompactCommandPad/CommandSelector.cpp index 24497f54ce7717ee724948c67d748ac13a866861..676340bb82e44dcbece1d076a03e7cb2c558da7b 100644 --- a/src/shared/Modules/CompactCommandPad/CommandSelector.cpp +++ b/src/shared/Modules/CompactCommandPad/CommandSelector.cpp @@ -19,6 +19,7 @@ #include "CommandSelector.h" #include <Modules/CommandPad/MessagesList.h> +#include <Modules/Mavlink/MavlinkCodec.h> #include <QDebug> @@ -40,6 +41,8 @@ XmlObject CommandSelector::toXmlObject(XmlObject& obj) if (ok) obj.addAttribute("timeout", QString() + timeout); + obj.addAttribute("target_system", systemsComboBox->currentText()); + auto key = messagesListComboBox->currentText(); if (formElements.contains(key)) { @@ -61,6 +64,13 @@ void CommandSelector::fromXmlObject(const XmlObject& obj) if (ok) continuosTimeoutEdit->setText(QString() + timeout); + auto targetSystem = obj.getAttribute("target_system"); + auto index = systemsComboBox->findText(targetSystem); + if (index >= 0) + { + systemsComboBox->setCurrentIndex(index); + } + if (obj.hasAttribute("message_id")) { auto key = obj.getAttribute("message_id"); @@ -70,8 +80,9 @@ void CommandSelector::fromXmlObject(const XmlObject& obj) formElements[key]->fromXmlObject(obj); messagesListComboBox->setCurrentText(key); - selectedMessage = formElements[key]->prepareMessage(key); - selectedLabel = obj.getAttribute("label"); + selectedMessage = formElements[key]->prepareMessage( + systemsComboBox->currentText(), key); + selectedLabel = obj.getAttribute("label"); lineEdit->setText(selectedLabel); selected = !selectedLabel.isEmpty(); } @@ -111,6 +122,15 @@ void CommandSelector::setupUi() continuosTimeoutEdit->setHidden(true); outerLayout->addWidget(continuosTimeoutEdit); + systemsComboBox = new QComboBox; + systemsComboBox->setSizePolicy( + QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + systemsComboBox->addItem("Main", MavlinkCodec::SysIdMain); + systemsComboBox->addItem("Payload", MavlinkCodec::SysIdPayload); + systemsComboBox->addItem("Rig", MavlinkCodec::SysIdRig); + systemsComboBox->addItem("Gs Receiver", MavlinkCodec::SysIdGsReceiver); + outerLayout->addWidget(systemsComboBox); + messagesListComboBox = new QComboBox; messagesListComboBox->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); @@ -170,9 +190,10 @@ void CommandSelector::setupUi() auto key = messagesListComboBox->currentText(); if (formElements.contains(key)) { - selectedMessage = formElements[key]->prepareMessage(key); - selectedLabel = lineEdit->text(); - selected = !selectedLabel.isEmpty(); + selectedMessage = formElements[key]->prepareMessage( + systemsComboBox->currentText(), key); + selectedLabel = lineEdit->text(); + selected = !selectedLabel.isEmpty(); if (selected) this->close(); diff --git a/src/shared/Modules/CompactCommandPad/CommandSelector.h b/src/shared/Modules/CompactCommandPad/CommandSelector.h index e15477adac652db3cba13565a9b4b260cfe245c2..d0453c0016091dc69bcdf513fed14f24f168daa3 100644 --- a/src/shared/Modules/CompactCommandPad/CommandSelector.h +++ b/src/shared/Modules/CompactCommandPad/CommandSelector.h @@ -52,6 +52,7 @@ private: QString currentMessage; QVBoxLayout* outerLayout; QLineEdit *lineEdit, *continuosTimeoutEdit; + QComboBox* systemsComboBox; QComboBox* messagesListComboBox; QMap<QString, MessageFormElement*> formElements; QGridLayout* formGridLayout; diff --git a/src/shared/Modules/Mavlink/BaseMavlinkModule.cpp b/src/shared/Modules/Mavlink/BaseMavlinkModule.cpp index 6215ce223ea868a341a12aa0f0dd86a64e358ff2..9e69bcd0a15599536cb3d9447afcc909b7d1721b 100644 --- a/src/shared/Modules/Mavlink/BaseMavlinkModule.cpp +++ b/src/shared/Modules/Mavlink/BaseMavlinkModule.cpp @@ -19,6 +19,12 @@ #include "BaseMavlinkModule.h" #include <Modules/SkywardHubStrings.h> +#include <qcombobox.h> +#include <qglobal.h> + +#include <utility> + +#include "Core/Message/Topic.h" int BaseMavlinkModule::ACTIVE_MAVLINK_MODULES = 0; @@ -31,11 +37,6 @@ BaseMavlinkModule::BaseMavlinkModule(MavlinkPort *port, ModuleId id) &BaseMavlinkModule::onMsgReceived); connect(&linkQualityTimer, &QTimer::timeout, this, &BaseMavlinkModule::onLinkQualityTimerTick); - - MessageBroker::getInstance().subscribe( - Filter::fromString(SkywardHubStrings::commandsTopic + "/*"), this, - [this](const Message &message, const Filter &filter) - { onCommandReceived(message); }); } BaseMavlinkModule::~BaseMavlinkModule() @@ -67,7 +68,20 @@ void BaseMavlinkModule::fromXmlObject(const XmlObject &obj) void BaseMavlinkModule::onMsgReceived(const Message &msg) { msgArrived++; - MessageBroker::getInstance().publish(msg); + + // The target system should always be selected when receiving a message + if (!targetSystem.has_value()) + { + error("Mavlink", + "No target system selected while receiving a message."); + } + + // Set the topic with the selected target system + auto msgFixed = msg; + msgFixed.setTopic( + Topic(targetSystem.value().first + "/In/" + msg.getTopic().toString())); + + MessageBroker::getInstance().publish(msgFixed); } void BaseMavlinkModule::onLinkQualityTimerTick() @@ -85,6 +99,33 @@ void BaseMavlinkModule::onStartStreamToggled(bool state) onStopClicked(); } +void BaseMavlinkModule::onTargetSysChanged(int itemIndex) +{ + QString sysName = sysIdComboBox->itemText(itemIndex); + MavlinkCodec::SysId sysId = static_cast<MavlinkCodec::SysId>( + sysIdComboBox->itemData(itemIndex).toInt()); + + // Unsubscribe from previous system + if (targetSystem.has_value()) + { + auto oldFilter = + Filter::fromString(targetSystem.value().first + "/Out/*"); + MessageBroker::getInstance().unsubscribe(oldFilter, this); + qDebug() << "Unsubscribed from " << oldFilter.toString(); + } + + // Subscribe to new system + auto newFilter = Filter::fromString(sysName + "/Out/*"); + MessageBroker::getInstance().subscribe( + newFilter, this, + [this](const Message &message, const Filter &filter) + { onCommandReceived(message); }); + qDebug() << "Subscribed to " << newFilter.toString(); + + // Update the target system + targetSystem = std::pair(sysName, sysId); +} + void BaseMavlinkModule::onStartClicked() { if (open()) @@ -120,8 +161,16 @@ void BaseMavlinkModule::onStopClicked() void BaseMavlinkModule::onCommandReceived(const Message &msg) { - MavlinkCodec::SysId sysId = - static_cast<MavlinkCodec::SysId>(sysIdComboBox->currentData().toInt()); + qDebug() << "Command received: " << msg.getTopic().toString() << " - " + << msg.toString(); + + if (!targetSystem.has_value()) + { + error(tr("Mavlink"), tr("No target system selected.")); + return; + } + + auto sysId = targetSystem.value().second; mavlink_message_t mav_msg; if (!mavlinkCodec.encodeMessage(msg, sysId, MavlinkCodec::CompIdNone, @@ -179,12 +228,14 @@ void BaseMavlinkModule::onOpenLogFolderClick() void BaseMavlinkModule::enableControls() { + sysIdComboBox->setEnabled(true); logCheckBox->setEnabled(true); childEnableControls(); } void BaseMavlinkModule::disableControls() { + sysIdComboBox->setEnabled(false); logCheckBox->setEnabled(false); childDisableControls(); } @@ -222,6 +273,10 @@ void BaseMavlinkModule::setupUi() sysIdComboBox->addItem("Gs Receiver", MavlinkCodec::SysIdGS); sysIdComboBox->addItem("ARP Receiver", MavlinkCodec::SysIdARP); outerLayout->addWidget(sysIdComboBox); + connect(sysIdComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), + this, &BaseMavlinkModule::onTargetSysChanged); + sysIdComboBox->setCurrentIndex(0); + onTargetSysChanged(0); childLayout = new QHBoxLayout; outerLayout->addLayout(childLayout); @@ -246,4 +301,4 @@ void BaseMavlinkModule::setupUi() &BaseMavlinkModule::onOpenLogFolderClick); setLayout(outerLayout); -} \ No newline at end of file +} diff --git a/src/shared/Modules/Mavlink/BaseMavlinkModule.h b/src/shared/Modules/Mavlink/BaseMavlinkModule.h index d7911d1022f2198163167981423f0463bba1132d..72739e554b63df50d02adb214ed25bcbf4286cce 100644 --- a/src/shared/Modules/Mavlink/BaseMavlinkModule.h +++ b/src/shared/Modules/Mavlink/BaseMavlinkModule.h @@ -24,6 +24,7 @@ #include <QTimer> #include <QWidget> +#include <optional> #include "MavlinkCodec.h" #include "Ports/MavlinkPort.h" @@ -53,10 +54,12 @@ protected: virtual bool open() = 0; QHBoxLayout *childLayout; + private slots: void onMsgReceived(const Message &msg); void onLinkQualityTimerTick(); void onStartStreamToggled(bool state); + void onTargetSysChanged(int itemIndex); private: void onStartClicked(); @@ -81,9 +84,11 @@ private: QLabel *rateLabel; QCheckBox *logCheckBox; + std::optional<std::pair<QString, MavlinkCodec::SysId>> targetSystem; + QTimer linkQualityTimer; const int linkQualityPeriod = 2000; // [ms] int msgArrived = 0; static int ACTIVE_MAVLINK_MODULES; -}; \ No newline at end of file +}; diff --git a/src/shared/Modules/Mavlink/MavlinkCodec.cpp b/src/shared/Modules/Mavlink/MavlinkCodec.cpp index 122c642f69f09063053fddd3d74b9d452839b5be..4b7fae49a7f9bc3a55874c3c8e16d4248afce825 100644 --- a/src/shared/Modules/Mavlink/MavlinkCodec.cpp +++ b/src/shared/Modules/Mavlink/MavlinkCodec.cpp @@ -18,6 +18,8 @@ #include "MavlinkCodec.h" +#include <qregularexpression.h> + #include <QDir> #include "BaseMavlinkModule.h" @@ -139,8 +141,7 @@ Message MavlinkCodec::decodeMessage(const mavlink_message_t& msg) Field(static_cast<uint64_t>(msg.compid)); Message output; - output.setTopic( - Topic(SkywardHubStrings::mavlink_received_msg_topic + "/" + info.name)); + output.setTopic(Topic(info.name)); output.setFields(std::move(fields)); return output; } @@ -247,9 +248,17 @@ Field MavlinkCodec::decodeArrayElement(const mavlink_message_t& msg, bool MavlinkCodec::encodeMessage(const Message& msg, SysId sysId, CompId compId, mavlink_message_t& output) { + QRegularExpression topicPattern("\\/((?:\\w|_)+)$"); + + auto matches = topicPattern.match(msg.getTopic().toString()); + + if (!matches.hasMatch()) + { + return false; + } + + QString messageName = matches.captured(1); - QString messageName = msg.getTopic().toString().replace( - SkywardHubStrings::commandsTopic + "/", ""); if (messageName == "PING_TC") { mavlink_msg_ping_tc_pack(