diff --git a/.vscode/settings.json b/.vscode/settings.json index d3abb169e8483de9d90cc454edb48266e06af854..fcde4c615a2f857fa3e7e9c86f802b52292760a0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -152,6 +152,7 @@ "editor.defaultFormatter": "redhat.vscode-xml" }, "cSpell.words": [ + "cppcheck", "entrypoints", "Mavlink", "Plottables", diff --git a/src/shared/Components/FilterSelector/FilterSelector.cpp b/src/shared/Components/FilterSelector/FilterSelector.cpp index 6439081dcbd496352af3043dfb416f62df97db6c..969ce367236e590118ebb3e638b0e876da92ba29 100644 --- a/src/shared/Components/FilterSelector/FilterSelector.cpp +++ b/src/shared/Components/FilterSelector/FilterSelector.cpp @@ -2,6 +2,7 @@ #include <Modules/Mavlink/MavlinkVersionHeader.h> +#include <QDebug> #include <QLabel> #include <QPushButton> @@ -12,26 +13,14 @@ void FilterSelector::setupUi() QVBoxLayout *layout = new QVBoxLayout; - QHBoxLayout *topicLayout = new QHBoxLayout; + QComboBox *topic = new QComboBox; + topic->setSizeAdjustPolicy(QComboBox::AdjustToContents); + topic->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + topic->addItems(messages.keys()); + layout->addWidget(topic); - QLabel *mainTopic = new QLabel; - mainTopic->setText("Mav"); - topicLayout->addWidget(mainTopic); - - QLabel *topicSeparator = new QLabel; - topicSeparator->setText("/"); - topicLayout->addWidget(topicSeparator); - - QComboBox *subTopic = new QComboBox; - subTopic->setSizeAdjustPolicy(QComboBox::AdjustToContents); - subTopic->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - subTopic->addItems(messages.keys()); - topicLayout->addWidget(subTopic, 1); - - layout->addLayout(topicLayout); - - fieldsLayout = new QVBoxLayout; - layout->addLayout(fieldsLayout); + fieldsWidget = new QListWidget; + layout->addWidget(fieldsWidget); QHBoxLayout *buttons = new QHBoxLayout; QPushButton *cancel = new QPushButton("Cancel"); @@ -41,17 +30,32 @@ void FilterSelector::setupUi() layout->addLayout(buttons); // Set default message - currentMessage = messages.keys().at(0); - subTopic->setCurrentText(currentMessage); - fieldsLayout->addWidget(fields[currentMessage]); + if (filter.getTopic().toString() != Topic().toString()) + { + currentMessage = filter.getTopic().toString(); + topic->setCurrentText(filter.getTopic().toString()); + } + else + { + currentMessage = messages.keys().at(0); + topic->setCurrentText(messages.keys().at(0)); + } - connect(subTopic, &QComboBox::currentTextChanged, this, + connect(topic, &QComboBox::currentTextChanged, this, [=](QString key) { if (messages.contains(key)) { - fieldsLayout->removeWidget(fields[currentMessage]); - fieldsLayout->addWidget(fields[key]); + fieldsWidget->clear(); + + fieldsWidget->addItems(messages[key]); + for (int i = 0; i < fieldsWidget->count(); i++) + { + auto item = fieldsWidget->item(i); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Unchecked); + } + currentMessage = key; } }); @@ -59,8 +63,14 @@ void FilterSelector::setupUi() connect(select, &QPushButton::clicked, [=]() { - Filter filter(Topic("Mav/" + subTopic->currentText())); - filter.addField(fields[currentMessage]->currentText()); + Filter filter(Topic(topic->currentText())); + + for (int i = 0; i < fieldsWidget->count(); i++) + { + auto item = fieldsWidget->item(i); + if (item->checkState()) + filter.addField(item->text()); + } emit filterSelected(filter); deleteLater(); @@ -110,15 +120,7 @@ void FilterSelector::parseMessagesList() for (unsigned int ii = 0; ii < messagesList[i].num_fields; ii++) fields.append(messagesList[i].fields[ii].name); - messages[messagesList[i].name] = fields; + messages[QString("Mav/") + messagesList[i].name] = fields; } } - - // Prepare fields combo boxes - for (auto messageName : messages.keys()) - { - auto comboBox = new QComboBox(); - comboBox->addItems(messages[messageName]); - fields[messageName] = comboBox; - } } diff --git a/src/shared/Components/FilterSelector/FilterSelector.h b/src/shared/Components/FilterSelector/FilterSelector.h index f1586d4c930ea85d6168dd1d5f1452b81066e58e..3b5ea4d122220596a7e3b6cc7617d0cdc5cf17dd 100644 --- a/src/shared/Components/FilterSelector/FilterSelector.h +++ b/src/shared/Components/FilterSelector/FilterSelector.h @@ -5,6 +5,7 @@ #include <QBoxLayout> #include <QComboBox> #include <QList> +#include <QListWidget> #include <QMap> #include <QString> @@ -28,10 +29,9 @@ private: Filter filter; QString currentMessage; - QVBoxLayout* fieldsLayout; + QListWidget* fieldsWidget; QMap<QString, QList<QString>> messages; - QMap<QString, QComboBox*> fields; signals: void filterSelected(const Filter&); diff --git a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp index 90def45996b75f8618169f18dd4ad58dc83a3edb..9d1b463e70b0806d19618facb518851fd852ae79 100644 --- a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp +++ b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp @@ -33,7 +33,7 @@ SubscriptionsPanel::SubscriptionsPanel(const QList<Filter>& filters) void SubscriptionsPanel::addFilter(const Filter& filter) { filtersList->addItem(new QListWidgetItem(filter.toString())); - emit topicAndFieldFilterAdded(filter); + emit filterAdded(filter); } void SubscriptionsPanel::setupUi() @@ -41,6 +41,8 @@ void SubscriptionsPanel::setupUi() QVBoxLayout* layout = new QVBoxLayout; filtersList = new QListWidget; + filtersList->setSelectionBehavior(QAbstractItemView::SelectItems); + filtersList->setSelectionMode(QAbstractItemView::SingleSelection); layout->addWidget(filtersList); QHBoxLayout* buttonsLayout = new QHBoxLayout; @@ -48,6 +50,9 @@ void SubscriptionsPanel::setupUi() QPushButton* addButton = new QPushButton; addButton->setText("Add filter"); buttonsLayout->addWidget(addButton); + QPushButton* editButton = new QPushButton; + editButton->setText("Edit filter"); + buttonsLayout->addWidget(editButton); QPushButton* removeButton = new QPushButton; removeButton->setText("Remove filter"); buttonsLayout->addWidget(removeButton); @@ -59,12 +64,27 @@ void SubscriptionsPanel::setupUi() connect(addButton, &QPushButton::clicked, this, [&]() { - FilterSelector::selectFilter( - [&](const Filter& filter) - { - qDebug() << "New filter:" << filter.toString(); - addFilter(filter); - }); + FilterSelector::selectFilter([&](const Filter& filter) + { addFilter(filter); }); + }); + connect(editButton, &QPushButton::clicked, this, + [&]() + { + if (filtersList->selectedItems().size() > 0) + { + auto item = filtersList->selectedItems().at(0); + + FilterSelector::selectFilter( + Filter::fromString(item->text()), + [=](const Filter& newFilter) + { + if (Filter::fromString(item->text()) != newFilter) + { + removeSubscription(item); + addFilter(newFilter); + } + }); + } }); connect(removeButton, &QPushButton::clicked, this, [&]() @@ -76,6 +96,6 @@ void SubscriptionsPanel::setupUi() void SubscriptionsPanel::removeSubscription(QListWidgetItem* item) { - emit topicAndFieldFilterRemoved(Filter::fromString(item->text())); + emit filterRemoved(Filter::fromString(item->text())); delete item; } diff --git a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h index 1fdff87822a011688d54ff2506c4072671d8b584..f39b186758d5962c11e912c35a6d7536904808bd 100644 --- a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h +++ b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h @@ -17,8 +17,8 @@ public: void addFilter(const Filter& filter); signals: - void topicAndFieldFilterAdded(const Filter&); - void topicAndFieldFilterRemoved(const Filter&); + void filterAdded(const Filter& filter); + void filterRemoved(const Filter& filter); private: void setupUi(); diff --git a/src/shared/Core/Message/Field.cpp b/src/shared/Core/Message/Field.cpp index 23f42935d26e1bf8bb5938b42165d1bef459f50a..8324a96219d621dc7f0d67c7ac1e177702500c5d 100644 --- a/src/shared/Core/Message/Field.cpp +++ b/src/shared/Core/Message/Field.cpp @@ -40,6 +40,10 @@ int64_t Field::getInteger() const { if (type == Type::INT) return signedInteger; + else if (type == Type::UINT) + return unsignedInteger; + else if (type == Type::DOUBLE) + return floatingPoint; else return 0; } @@ -48,6 +52,10 @@ uint64_t Field::getUnsignedInteger() const { if (type == Type::UINT) return unsignedInteger; + else if (type == Type::INT) + return signedInteger; + else if (type == Type::DOUBLE) + return floatingPoint; else return 0; } @@ -56,18 +64,14 @@ double Field::getDouble() const { if (type == Type::DOUBLE) return floatingPoint; + else if (type == Type::INT) + return signedInteger; + else if (type == Type::UINT) + return unsignedInteger; else return 0; } -QString Field::getString() const -{ - if (type == Type::STRING) - return string; - else - return QString(); -} - QString Field::toString() const { switch (type) diff --git a/src/shared/Core/Message/Field.h b/src/shared/Core/Message/Field.h index 50d0af6103534e40cf11204dadd9a65e430dfda6..b1210bb05ab6084d8a383232475f969ab48bebc7 100644 --- a/src/shared/Core/Message/Field.h +++ b/src/shared/Core/Message/Field.h @@ -26,18 +26,12 @@ public: Type getType() const; - /// @brief Returns value if the field is of type INT int64_t getInteger() const; - /// @brief Returns value if the field is of type UINT uint64_t getUnsignedInteger() const; - /// @brief Returns value if the field is of type DOUBLE double getDouble() const; - /// @brief Returns value if the field is of type STRING - QString getString() const; - QString toString() const; private: diff --git a/src/shared/Core/Message/Filter.cpp b/src/shared/Core/Message/Filter.cpp index 85acceeedf25310474764ba2e8fd2a4adfd76d88..4bda55506ecd0915a2032621c2db71084c8632e4 100644 --- a/src/shared/Core/Message/Filter.cpp +++ b/src/shared/Core/Message/Filter.cpp @@ -10,14 +10,17 @@ Filter::Filter(Topic topic, QSet<QString> fields) : topic(topic), fields(fields) bool Filter::operator==(const Filter& toCompare) const { - return topic == toCompare.topic && - ((fields.isEmpty() && toCompare.fields.isEmpty()) || - (fields == toCompare.fields)); + return toString() == toCompare.toString(); +} + +bool Filter::operator!=(const Filter& toCompare) const +{ + return !(*this == toCompare); } bool Filter::operator<(const Filter& toCompare) const { - return topic < toCompare.topic; + return toString() < toCompare.toString(); } void Filter::setTopic(Topic topic) { this->topic = topic; } diff --git a/src/shared/Core/Message/Filter.h b/src/shared/Core/Message/Filter.h index c086b769a239f34a69e438f885a5d9f762a4c79b..d3f5d0c5c8ae230ac1738542c0da62a2394a331b 100644 --- a/src/shared/Core/Message/Filter.h +++ b/src/shared/Core/Message/Filter.h @@ -24,6 +24,7 @@ public: Filter(Topic topic, QSet<QString> fields); bool operator==(const Filter& toCompare) const; + bool operator!=(const Filter& toCompare) const; bool operator<(const Filter& toCompare) const; void setTopic(Topic topic); diff --git a/src/shared/Core/Message/Message.cpp b/src/shared/Core/Message/Message.cpp index 8da9c4efd3ab81a2308c615519064cd3784186f2..278ef8da323ddbafb17989e957900adadecc0272 100644 --- a/src/shared/Core/Message/Message.cpp +++ b/src/shared/Core/Message/Message.cpp @@ -10,7 +10,13 @@ Topic Message::getTopic() const { return topic; } void Message::setField(QString key, const Field& field) { fields[key] = field; } -Field Message::getField(QString key) const { return fields[key]; } +Field Message::getField(QString key) const +{ + if (fields.contains(key)) + return fields[key]; + else + return Field(); +} bool Message::removeField(QString key) { return fields.remove(key); } diff --git a/src/shared/Core/MessageBroker/MessageBroker.cpp b/src/shared/Core/MessageBroker/MessageBroker.cpp index 9aeb1ac78744b2145239126e1af5ab2d95818e17..226fa93902e6877e872ac97c2b2933be8634ae43 100644 --- a/src/shared/Core/MessageBroker/MessageBroker.cpp +++ b/src/shared/Core/MessageBroker/MessageBroker.cpp @@ -2,8 +2,6 @@ #include <Core/Module/Module.h> -#include <QDebug> - void MessageBroker::subscribe(Filter filter, Module* observer, Callback callback) { @@ -13,8 +11,6 @@ void MessageBroker::subscribe(Filter filter, Module* observer, // subscriber connect(observer->getEventHandler(), &EventHandler::beforeDelete, this, &MessageBroker::onModuleDeleted); - - qDebug() << "Added subscription: " << filter.toString(); } void MessageBroker::unsubscribe(Filter filter, Module* module) @@ -39,7 +35,7 @@ void MessageBroker::publish(const Message& message) { auto copy = message; filter.filterMessage(copy); - (*subscriber.second)(copy); + (*subscriber.second)(copy, filter); } } } diff --git a/src/shared/Core/MessageBroker/MessageBroker.h b/src/shared/Core/MessageBroker/MessageBroker.h index ada2a4fc94d7c64481c0c22ccc3127b4339dc058..eee290fbc51c007bc438808fd6d0172ada3edd16 100644 --- a/src/shared/Core/MessageBroker/MessageBroker.h +++ b/src/shared/Core/MessageBroker/MessageBroker.h @@ -12,7 +12,7 @@ class MessageBroker : public QObject Q_OBJECT public: - using Callback = std::function<void(const Message& msg)>; + using Callback = std::function<void(const Message&, const Filter&)>; void subscribe(Filter filter, Module* observer, Callback callback); diff --git a/src/shared/Core/ModulesManager/ModulesManager.cpp b/src/shared/Core/ModulesManager/ModulesManager.cpp index a4b809facd58ccee8e737d3f9026c8502cadb5c7..55533318d0c935980d1cdfd520929538f8048b1f 100644 --- a/src/shared/Core/ModulesManager/ModulesManager.cpp +++ b/src/shared/Core/ModulesManager/ModulesManager.cpp @@ -200,8 +200,6 @@ void ModulesManager::onReplaceMeWith(Module* sender, Module* newModule) pages[index] = newModule; connectModule(newModule); disconnectModule(sender); - // TODO: Understand well how the all this mess works - // delete sender; } } } diff --git a/src/shared/Modules/FileStream/FileStreamModule.cpp b/src/shared/Modules/FileStream/FileStreamModule.cpp index 609d61b7846dddcf892abc1cdcd40174199ae8eb..a1fcf669aa15c0ff2b7fab5823221d13b38a80e6 100644 --- a/src/shared/Modules/FileStream/FileStreamModule.cpp +++ b/src/shared/Modules/FileStream/FileStreamModule.cpp @@ -134,7 +134,8 @@ void FileStreamModule::onStartClicked() { getCore()->getMessageBroker()->subscribe( Filter::fromString(topicViewsList[i]->text().trimmed()), this, - [this](const Message& msg) { onMsgReceived(msg); }); + [this](const Message& message, const Filter& filter) + { onMsgReceived(message); }); topicViewsList[i]->setEnabled(false); } } diff --git a/src/shared/Modules/Graph/Graph.cpp b/src/shared/Modules/Graph/Graph.cpp index 17c56cbf1d1418d0985e1ca41477838c32c02ca3..e49e6598305d0a657d72add10450e864067674f6 100644 --- a/src/shared/Modules/Graph/Graph.cpp +++ b/src/shared/Modules/Graph/Graph.cpp @@ -4,6 +4,7 @@ #include <Components/SubscriptionsPanel/SubscriptionsPanel.h> #include <Core/MessageBroker/MessageBroker.h> +#include <QDebug> #include <QTimer> #include <algorithm> @@ -15,14 +16,8 @@ Graph::Graph(QWidget* parent) : DefaultModule(parent) connect(&updaterTimer, &QTimer::timeout, this, &Graph::onUpdateTimerTick); updaterTimer.setSingleShot(false); updaterTimer.start(updatePeriod); - - getCore()->getMessageBroker()->subscribe(Filter::fromString("*"), this, - [this](const Message& msg) - { onMsgReceived(msg); }); } -Graph::~Graph() {} - QWidget* Graph::toWidget() { return this; } XmlObject Graph::toXmlObject() @@ -36,10 +31,10 @@ XmlObject Graph::toXmlObject() obj.addAttribute("x_lower_range", (float)plot->xAxis->range().lower); obj.addAttribute("x_upper_range", (float)plot->xAxis->range().upper); - for (int i = 0; i < filters.count(); i++) + for (auto filter : lines.keys()) { XmlObject element("subscription"); - element.addAttribute("filter", filters[i].toString()); + element.addAttribute("filter", filter.toString()); obj.addChild(element); } @@ -71,7 +66,7 @@ void Graph::fromXmlObject(const XmlObject& obj) if (child.getObjectName() == "subscription") { auto filter = Filter::fromString(child.getAttribute("filter")); - onSubscriptionAdded(filter); + onFilterAdded(filter); } } } @@ -79,19 +74,23 @@ void Graph::fromXmlObject(const XmlObject& obj) void Graph::onSubscribeClicked() { - SubscriptionsPanel* panel = new SubscriptionsPanel(filters); + SubscriptionsPanel* panel = new SubscriptionsPanel(lines.keys()); panel->setWindowTitle("Graph subscriptions"); - connect(panel, &SubscriptionsPanel::topicAndFieldFilterAdded, this, - &Graph::onSubscriptionAdded); - connect(panel, &SubscriptionsPanel::topicAndFieldFilterRemoved, this, - &Graph::onSubscriptionRemoved); + connect(panel, &SubscriptionsPanel::filterAdded, this, + &Graph::onFilterAdded); + connect(panel, &SubscriptionsPanel::filterRemoved, this, + &Graph::onFilterRemoved); panel->show(); } void Graph::onClearClicked() { - for (auto graph : graphs) - graph->data()->clear(); + for (auto filter : lines.keys()) + { + for (auto field : lines[filter].first.keys()) + lines[filter].first[field].graph->data()->clear(); + } + plot->replot(); } @@ -107,38 +106,86 @@ void Graph::onStopClicked(bool checked) void Graph::onFollowClicked(bool checked) { following = checked; } -void Graph::onSubscriptionAdded(const Filter& filter) +void Graph::onFilterAdded(const Filter& filter) { - if (!filters.contains(filter)) + qDebug() << "[Graph] On filter added"; + + // Fail if the filter is already in the list + if (lines.keys().contains(filter)) { + qDebug() << "[Graph] Filter already in the list"; + return; + } + + // Add a new line for each field of the filter + for (auto field : filter.getFields()) + { + // Create the graph QCPGraph* graph = plot->addGraph(); graph->setPen( QPen(QColor(rand() % 255, rand() % 255, rand() % 255), 2)); graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssNone, 2)); graph->setSelectable(QCP::stNone); - graph->setName(filter.toString()); + graph->setName(field); - // Add the filter and the graph along with new buffers - filters.append(filter); - graphs.append(graph); - buffersX.append(QVector<double>()); - buffersY.append(QVector<double>()); + // Add the filter and the graph along with new buffers to the lists + lines[filter].first[field] = {graph, QVector<double>(), + QVector<double>()}; } + + getCore()->getMessageBroker()->subscribe( + filter, this, + [&](const Message& message, const Filter& filter) + { + qDebug() << "[Graph] Received new message:" << message.toString(); + + if (stopped && !lines.contains(filter)) + return; + + for (auto field : filter.getFields()) + { + auto& line = lines[filter].first[field]; + + QVector<double>& bufferX = line.bufferX; + QVector<double>& bufferY = line.bufferY; + + double x = + message.getField("timestamp").getUnsignedInteger() / 1e6; + double y = message.getField(field).getDouble(); + + // Check if the timestamp resets + if (bufferX.last() < x) + { + bufferX.append(x); + bufferY.append(y); + } + else + { + bufferX.clear(); + bufferY.clear(); + + line.graph->data()->clear(); + } + } + + // Flag the data as updated + lines[filter].second = true; + }); } -void Graph::onSubscriptionRemoved(const Filter& filter) +void Graph::onFilterRemoved(const Filter& filter) { - if (filters.contains(filter)) + if (lines.contains(filter)) { - int index = filters.indexOf(filter); + for (auto field : lines[filter].first.keys()) + { + auto line = lines[filter].first[field]; - plot->removeGraph(graphs[index]); - plot->replot(); + plot->removeGraph(line.graph); + plot->replot(); + } - filters.removeAt(index); - graphs.removeAt(index); - buffersX.removeAt(index); - buffersY.removeAt(index); + lines.remove(filter); } } @@ -148,29 +195,33 @@ void Graph::onUpdateTimerTick() double maxX = 0; // Check if new data items are available and redraw - for (int i = 0; i < filters.size(); i++) + for (auto filter : lines.keys()) { - QCPGraph* graph = graphs[i]; - QVector<double>& bufferX = buffersX[i]; - - if (bufferX.size() > 0) + // Check if the data have been updated + if (lines[filter].second) { - QVector<double>& bufferY = buffersY[i]; + for (auto field : lines[filter].first.keys()) + { + auto& line = lines[filter].first[field]; - newData = true; + if (line.bufferX.size() > 0) + { + newData = true; - graph->addData(bufferX, bufferY); + line.graph->addData(line.bufferX, line.bufferY); - for (auto tmp : bufferX) - if (tmp > maxX) - // cppcheck-suppress useStlAlgorithm - maxX = tmp; + for (auto tmp : line.bufferX) + if (tmp > maxX) + // cppcheck-suppress useStlAlgorithm + maxX = tmp; - bufferX.clear(); - bufferY.clear(); + line.bufferX.clear(); + line.bufferY.clear(); - // Check if there are too many data points - graph->data()->removeBefore(maxX - MAX_DATA_AGE); + // Check if there are too many data points + line.graph->data()->removeBefore(maxX - MAX_DATA_AGE); + } + } } } @@ -179,47 +230,8 @@ void Graph::onUpdateTimerTick() plot->replot(); if (following) - { - double size = plot->xAxis->range().size(); - plot->xAxis->setRange(maxX, size, Qt::AlignmentFlag::AlignRight); - } - } -} - -void Graph::onMsgReceived(const Message& msg) -{ - if (stopped) - return; - - // TODO - - for (auto filter : filters) - { - if (filter.match(msg)) - { - int index = filters.indexOf(filter); - - QVector<double>& bufferX = buffersX[index]; - QVector<double>& bufferY = buffersY[index]; - - double x = msg.getField("timestamp").getUnsignedInteger() / 1e6; - double y = 2; // TODO - - // Check if the timestamp resets - if (bufferX.last() < x) - { - bufferX.append(x); - bufferY.append(y); - } - else - { - bufferX.clear(); - bufferY.clear(); - - auto graph = graphs[index]; - graph->data()->clear(); - } - } + plot->xAxis->setRange(maxX, plot->xAxis->range().size(), + Qt::AlignmentFlag::AlignRight); } } @@ -256,7 +268,7 @@ void Graph::onCustomContextMenuRequested(const QPoint& pos) QMenu menu; // Subscribe -> Edit graph series - QAction* subscribe = new QAction("Subscribe"); + QAction* subscribe = new QAction("Manage subscriptions"); connect(subscribe, &QAction::triggered, this, &Graph::onSubscribeClicked); menu.addAction(subscribe); diff --git a/src/shared/Modules/Graph/Graph.h b/src/shared/Modules/Graph/Graph.h index edb741816d2b0416d6fcb517702bc260e6c59f7b..4b0c551d2d72633335291f7ddcd92e371c2da606 100644 --- a/src/shared/Modules/Graph/Graph.h +++ b/src/shared/Modules/Graph/Graph.h @@ -1,8 +1,6 @@ #pragma once #include <Core/Message/Filter.h> -#include <Core/Message/Message.h> -#include <Core/Module/Module.h> #include <Core/QCustomPlot/QCustomPlot.h> #include <Modules/DefaultModule/DefaultModule.h> @@ -18,7 +16,6 @@ class Graph : public DefaultModule public: explicit Graph(QWidget* parent = nullptr); - ~Graph(); QWidget* toWidget() override; XmlObject toXmlObject() override; @@ -29,10 +26,11 @@ private slots: void onClearClicked(); void onStopClicked(bool checked); void onFollowClicked(bool checked); - void onSubscriptionAdded(const Filter& filter); - void onSubscriptionRemoved(const Filter& filter); + + void onFilterAdded(const Filter& filter); + void onFilterRemoved(const Filter& filter); + void onUpdateTimerTick(); - void onMsgReceived(const Message& msg); private: void setupUi(); @@ -41,10 +39,14 @@ private: QCustomPlot* plot; - QList<Filter> filters; - QList<QCPGraph*> graphs; - QList<QVector<double>> buffersX; - QList<QVector<double>> buffersY; + struct Line + { + QCPGraph* graph; + QVector<double> bufferX; + QVector<double> bufferY; + }; + + QMap<Filter, QPair<QMap<QString, Line>, bool>> lines; QTimer updaterTimer; int updatePeriod = 1000 / 5; // 5fps diff --git a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp index c43042b8e5117b753f4b12cfdff80638ec8411bf..1281433534887e5336cfbc2af558fbe67a15a875 100644 --- a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp +++ b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp @@ -48,18 +48,30 @@ void IncomingMessagesViewerModule::fromXmlObject(const XmlObject& xmlObject) { XmlObject child = xmlObject.childAt(i); if (child.getObjectName() == "subscription") - addSubscription(Filter::fromString(child.getAttribute("filter"))); + onFilterAdded(Filter::fromString(child.getAttribute("filter"))); } } -void IncomingMessagesViewerModule::addSubscription(const Filter& filter) +void IncomingMessagesViewerModule::onSubscribeClicked() +{ + SubscriptionsPanel* panel = new SubscriptionsPanel(filters); + panel->setWindowTitle("Graph subscriptions"); + connect(panel, &SubscriptionsPanel::filterAdded, this, + &IncomingMessagesViewerModule::onFilterAdded); + connect(panel, &SubscriptionsPanel::filterRemoved, this, + &IncomingMessagesViewerModule::onFilterRemoved); + panel->show(); +} + +void IncomingMessagesViewerModule::onFilterAdded(const Filter& filter) { - qDebug() << "addSubscription"; filters.append(filter); getCore()->getMessageBroker()->subscribe( filter, this, - [&](const Message& msg) + [&](const Message& message, const Filter& filter) { + qDebug() << "[Graph] Received new message:" << message.toString(); + QString oldText = ""; QString time = ""; @@ -70,7 +82,7 @@ void IncomingMessagesViewerModule::addSubscription(const Filter& filter) if (useTimestamp) { // If available show the timestamp - auto timestamp = msg.getField("timestamp"); + auto timestamp = message.getField("timestamp"); time += "["; time += QString::number( (float)timestamp.getUnsignedInteger() / 1e6, 'f', 1); @@ -82,36 +94,38 @@ void IncomingMessagesViewerModule::addSubscription(const Filter& filter) } // Updated the content - edit->setText(time + msg.toString() + "\n" + oldText); + edit->setText(time + message.toString() + "\n" + oldText); }); } -void IncomingMessagesViewerModule::removeSubscription(const Filter& filter) +void IncomingMessagesViewerModule::onFilterRemoved(const Filter& filter) { filters.removeAll(filter); getCore()->getMessageBroker()->unsubscribe(filter, this); } +void IncomingMessagesViewerModule::setupUi() +{ + edit = new QTextEdit(); + edit->setReadOnly(true); + edit->setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); + + QHBoxLayout* layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(edit); + setLayout(layout); +} + void IncomingMessagesViewerModule::addCustomActionsToMenu() { QAction* clear = new QAction("Clear"); connect(clear, &QAction::triggered, this, [this]() { edit->clear(); }); addActionToMenu(clear); - QAction* manage = new QAction("Manage subscriptions"); - connect(manage, &QAction::triggered, this, - [this]() - { - auto* panel = new SubscriptionsPanel(filters); - panel->setWindowTitle("IncomingMessagesViewer subscriptions"); - connect(panel, &SubscriptionsPanel::topicAndFieldFilterAdded, - this, &IncomingMessagesViewerModule::addSubscription); - connect(panel, &SubscriptionsPanel::topicAndFieldFilterRemoved, - this, - &IncomingMessagesViewerModule::removeSubscription); - panel->show(); - }); - addActionToMenu(manage); + QAction* subscriptions = new QAction("Manage subscriptions"); + connect(subscriptions, &QAction::triggered, this, + &IncomingMessagesViewerModule::onSubscribeClicked); + addActionToMenu(subscriptions); keepOnlyLastMessageAction = new QAction("Keep only last message"); keepOnlyLastMessageAction->setCheckable(true); @@ -125,15 +139,3 @@ void IncomingMessagesViewerModule::addCustomActionsToMenu() [=](bool value) { useTimestamp = value; }); addActionToMenu(useTimestampAction); } - -void IncomingMessagesViewerModule::setupUi() -{ - edit = new QTextEdit(); - edit->setReadOnly(true); - edit->setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); - - QHBoxLayout* layout = new QHBoxLayout(); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(edit); - setLayout(layout); -} diff --git a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h index 4333f0a54ee78aef64710df14039032cf4735161..9b951e3ecbbc250666f8f24d0dd4aa36b17b1ab8 100644 --- a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h +++ b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h @@ -15,15 +15,16 @@ public: XmlObject toXmlObject() override; void fromXmlObject(const XmlObject& xmlObject) override; - void addCustomActionsToMenu() override; -public slots: - void addSubscription(const Filter& filter); - void removeSubscription(const Filter& filter); +private slots: + void onSubscribeClicked(); + void onFilterAdded(const Filter& filter); + void onFilterRemoved(const Filter& filter); private: QTextEdit* edit; void setupUi(); + void addCustomActionsToMenu() override; QList<Filter> filters; diff --git a/src/shared/Modules/Mavlink/MavlinkModule.cpp b/src/shared/Modules/Mavlink/MavlinkModule.cpp index ecdc16fb85dfb5d6fd8394360466263e1733950c..7dccbb99fccfd5a69ec4b07de7a9c11719d9f152 100644 --- a/src/shared/Modules/Mavlink/MavlinkModule.cpp +++ b/src/shared/Modules/Mavlink/MavlinkModule.cpp @@ -24,7 +24,8 @@ MavlinkModule::MavlinkModule(QWidget *parent) getCore()->getMessageBroker()->subscribe( Filter::fromString(SkywardHubStrings::commandsTopic + "/*"), this, - [this](const Message &msg) { onCommandReceived(msg); }); + [this](const Message &message, const Filter &filter) + { onCommandReceived(message); }); } MavlinkModule::~MavlinkModule() { onStopClicked(); } diff --git a/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp b/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp index 1aea11c59d7dc272371477f8a31ee03800bfd579..5b14d10255aff1da81b5e800b0a3bc5c805de9b4 100644 --- a/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp +++ b/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp @@ -30,12 +30,12 @@ OrientationVisualizer::OrientationVisualizer(QWidget *parent) getCore()->getMessageBroker()->subscribe( Filter::fromString("Mav/PAYLOAD_FLIGHT_TM"), this, - [this](const Message &msg) + [this](const Message &message, const Filter &filter) { - updateOrientation(msg.getField("nas_qx").getDouble(), - msg.getField("nas_qy").getDouble(), - msg.getField("nas_qz").getDouble(), - msg.getField("nas_qw").getDouble()); + updateOrientation(message.getField("nas_qx").getDouble(), + message.getField("nas_qy").getDouble(), + message.getField("nas_qz").getDouble(), + message.getField("nas_qw").getDouble()); }); } diff --git a/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp b/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp index 3174a00de00ef409611365cce43ccff45ade744b..b1af15a228b580251b75422df4d2b7a8094a906f 100644 --- a/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp +++ b/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp @@ -15,14 +15,19 @@ OutgoingMessagesViewerModule::OutgoingMessagesViewerModule(QWidget* parent) getCore()->getMessageBroker()->subscribe( Filter::fromString(SkywardHubStrings::logCommandsTopic), this, - [this](const Message& msg) { addMsgSent(msg); }); + [this](const Message& message, const Filter& filter) + { addMsgSent(message); }); getCore()->getMessageBroker()->subscribe( Filter::fromString(SkywardHubStrings::mavlink_received_msg_ACK_topic), - this, [this](const Message& msg) { handleAck(msg); }); + this, + [this](const Message& message, const Filter& filter) + { handleAck(message); }); getCore()->getMessageBroker()->subscribe( Filter::fromString(SkywardHubStrings::mavlink_received_msg_NACK_topic), - this, [this](const Message& msg) { handleNack(msg); }); + this, + [this](const Message& message, const Filter& filter) + { handleNack(message); }); } OutgoingMessagesViewerModule::~OutgoingMessagesViewerModule() { delete ui; } @@ -54,7 +59,7 @@ void OutgoingMessagesViewerModule::addMsgSent(const Message& msg) QString OutgoingMessagesViewerModule::computeMsgName(const Message& msg) { - return msg.getField("name").getString(); + return msg.getField("name").toString(); } void OutgoingMessagesViewerModule::handleAck(const Message& ack) diff --git a/src/shared/Modules/StateViewer/StateViewer.cpp b/src/shared/Modules/StateViewer/StateViewer.cpp index f1f2cb2567db24133353b56acf64c4af07462224..870c2128bd5d6c6d70c8109190d8c067ad242a3f 100644 --- a/src/shared/Modules/StateViewer/StateViewer.cpp +++ b/src/shared/Modules/StateViewer/StateViewer.cpp @@ -71,7 +71,9 @@ void StateViewerModule::setFilter(const Filter& newFilter) { getCore()->getMessageBroker()->unsubscribe(filter, this); getCore()->getMessageBroker()->subscribe( - newFilter, this, [this](const Message& msg) { onMsgReceived(msg); }); + newFilter, this, + [this](const Message& message, const Filter& filter) + { onMsgReceived(message); }); filter = newFilter; } diff --git a/src/shared/Modules/Test/TestModule.cpp b/src/shared/Modules/Test/TestModule.cpp index 6e78e8e92990d731c0f9eb0a96fd41436bd034f7..e87a2bbedd475c8cc2b0590a8583b806d9b94687 100644 --- a/src/shared/Modules/Test/TestModule.cpp +++ b/src/shared/Modules/Test/TestModule.cpp @@ -35,25 +35,25 @@ void TestModule::on_publish_button_clicked() { QString topic = ui->topic_lineEdit->text().trimmed(); QString payload = ui->payload_lineEdit->text().trimmed(); - Message msg(Topic{topic}); + Message message(Topic{topic}); auto valueField = Field(payload); - msg.setField("value", valueField); + message.setField("value", valueField); auto timestampField = Field((uint64_t)QTime::currentTime().msecsSinceStartOfDay()); - msg.setField("timestamp", timestampField); - getCore()->getMessageBroker()->publish(msg); + message.setField("timestamp", timestampField); + getCore()->getMessageBroker()->publish(message); } void TestModule::on_subscribe_button_clicked() { getCore()->getMessageBroker()->subscribe( Filter::fromString(ui->subscribe_lineEdit->text().trimmed()), this, - [this](const Message& msg) + [this](const Message& message, const Filter& filter) { QString oldText = ui->textArea->toPlainText(); QString line = QDateTime::currentDateTime().toString("hh.mm.ss (zzz): ") + - msg.toString(); + message.toString(); QString newText(line + '\n' + oldText); ui->textArea->setPlainText(newText.mid(0, maxChar)); }); diff --git a/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp b/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp index 1109c5a8ad959e7d87d31daaa1ffb50fe56b6076..6a870b348516016e7b56424433735c908f06e44e 100644 --- a/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp +++ b/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp @@ -12,9 +12,10 @@ ValuesConverterViewerModule::ValuesConverterViewerModule(QWidget* parent) ui->setupUi(this); defaultContextMenuSetup(); - getCore()->getMessageBroker()->subscribe(Filter::fromString("*"), this, - [this](const Message& msg) - { onMsgReceived(msg); }); + getCore()->getMessageBroker()->subscribe( + Filter::fromString("*"), this, + [this](const Message& message, const Filter& filter) + { onMsgReceived(message); }); } ValuesConverterViewerModule::~ValuesConverterViewerModule()