From a020f388ff472e91d44a6734de5f097fe3e3314e Mon Sep 17 00:00:00 2001
From: Matteo Pignataro <matteo.pignataro@skywarder.eu>
Date: Thu, 31 Aug 2023 16:01:43 +0000
Subject: [PATCH] [ValvesViewer] Added RIG valves viewer

---
 CMakeLists.txt                                |   1 +
 SkywardHub.pro                                |   3 +
 src/shared/Modules/ModuleInfo.h               |   1 +
 src/shared/Modules/ModulesList.cpp            |   7 +
 src/shared/Modules/ValvesViewer/ValvesList.h  |  45 ++++++
 .../Modules/ValvesViewer/ValvesViewer.cpp     | 136 ++++++++++++++++++
 .../Modules/ValvesViewer/ValvesViewer.h       |  54 +++++++
 7 files changed, 247 insertions(+)
 create mode 100644 src/shared/Modules/ValvesViewer/ValvesList.h
 create mode 100644 src/shared/Modules/ValvesViewer/ValvesViewer.cpp
 create mode 100644 src/shared/Modules/ValvesViewer/ValvesViewer.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc328c0c..64a4c4a4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,6 +86,7 @@ add_executable(groundstation
     src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.cpp
     src/shared/Modules/ModuleInfo.cpp
     src/shared/Modules/ModulesList.cpp
+    src/shared/Modules/ValvesViewer/ValvesViewer.cpp
     src/entrypoints/groundstation/application.qrc
     src/entrypoints/groundstation/main.cpp
 )
diff --git a/SkywardHub.pro b/SkywardHub.pro
index 479c8174..ba8d17d2 100644
--- a/SkywardHub.pro
+++ b/SkywardHub.pro
@@ -48,6 +48,7 @@ SOURCES += \
     src/shared/Modules/Mavlink/MavlinkReader.cpp \
     src/shared/Modules/Mavlink/MavlinkCommandAdapter.cpp \
     src/shared/Modules/Mavlink/MavlinkModule.cpp \
+    src/shared/Modules/ValvesViewer/ValvesViewer.cpp \
     src/shared/Core/EventHandler/EventHandler.cpp \
     src/shared/Core/XmlObject.cpp \
     src/shared/Core/QCustomPlot/QCustomPlot.cpp \
@@ -102,6 +103,8 @@ HEADERS += \
     src/shared/Modules/Mavlink/MavlinkModule.h \
     src/shared/Modules/Mavlink/MavlinkCommandAdapter.h \
     src/shared/Modules/ModulesList.h \
+    src/shared/Modules/ValvesViewer/ValvesViewer.h \
+    src/shared/Modules/ValvesViewer/ValvesList.h \
     src/shared/Core/EventHandler/EventHandler.h \
     src/shared/Core/QCustomPlot/QCustomPlot.h \
     src/shared/Core/MessageBroker/MessageBroker.h \
diff --git a/src/shared/Modules/ModuleInfo.h b/src/shared/Modules/ModuleInfo.h
index f300c0ac..75907750 100644
--- a/src/shared/Modules/ModuleInfo.h
+++ b/src/shared/Modules/ModuleInfo.h
@@ -41,6 +41,7 @@ enum ModuleId
     MODULETEST,
     TABS,
     FILTER_SELECTOR,
+    VALVESVIEWER,
 };
 
 enum ModuleCategory
diff --git a/src/shared/Modules/ModulesList.cpp b/src/shared/Modules/ModulesList.cpp
index d32058bd..666fadd8 100644
--- a/src/shared/Modules/ModulesList.cpp
+++ b/src/shared/Modules/ModulesList.cpp
@@ -35,6 +35,7 @@
 #include <Modules/Test/TestModule.h>
 #include <Modules/TimerController/TimerControllerModule.h>
 #include <Modules/ValuesConverterViewer/ValuesConverterViewerModule.h>
+#include <Modules/ValvesViewer/ValvesViewer.h>
 
 void ModulesList::createModuleList()
 {
@@ -130,6 +131,12 @@ void ModulesList::createModuleList()
     ModuleInfo tabs(ModuleId::TABS, "Tabs", ModuleCategory::UTILITY);
     tabs.setFactory([]() { return new TabsModule(); });
     addModuleInfo(tabs);
+
+    ModuleInfo valvesViewer(ModuleId::VALVESVIEWER, "ValvesViewer",
+                            ModuleCategory::DATAVISUAL);
+    valvesViewer.setFactory([]() { return new ValvesViewer(); });
+    valvesViewer.addModuleSourceFiles("Modules/ValvesViewer/");
+    addModuleInfo(valvesViewer);
 }
 
 // ____________________________________________________________________________________________
diff --git a/src/shared/Modules/ValvesViewer/ValvesList.h b/src/shared/Modules/ValvesViewer/ValvesList.h
new file mode 100644
index 00000000..16fe15ef
--- /dev/null
+++ b/src/shared/Modules/ValvesViewer/ValvesList.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of Skyward Hub.
+ *
+ * Skyward Hub 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, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Skyward Hub 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 for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Skyward Hub. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <QList>
+#include <QMap>
+#include <QString>
+
+namespace ValvesList
+{
+
+// Valves
+enum class Valve : int
+{
+    FILLING = 0,
+    RELEASE,
+    VENTING,
+    MAIN,
+};
+
+// Groundstation labels
+static const QList<QString> valvesLabels{
+    "FILLING",
+    "RELEASE",
+    "VENTING",
+    "MAIN",
+};
+
+}  // namespace ValvesList
\ No newline at end of file
diff --git a/src/shared/Modules/ValvesViewer/ValvesViewer.cpp b/src/shared/Modules/ValvesViewer/ValvesViewer.cpp
new file mode 100644
index 00000000..71169955
--- /dev/null
+++ b/src/shared/Modules/ValvesViewer/ValvesViewer.cpp
@@ -0,0 +1,136 @@
+/*
+ * This file is part of Skyward Hub.
+ *
+ * Skyward Hub 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, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Skyward Hub 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 for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Skyward Hub. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "ValvesViewer.h"
+
+#include <Components/FilterSelector/FilterSelector.h>
+#include <Core/MessageBroker/MessageBroker.h>
+
+ValvesViewer::ValvesViewer(QWidget* parent) : DefaultModule(parent)
+{
+    setupUi();
+    defaultContextMenuSetup();
+}
+
+ValvesViewer::~ValvesViewer()
+{
+    getCore()->getMessageBroker()->unsubscribe(filter, this);
+}
+
+QWidget* ValvesViewer::toWidget() { return this; }
+
+XmlObject ValvesViewer::toXmlObject()
+{
+    XmlObject obj(getName(ModuleId::VALVESVIEWER));
+
+    obj.addAttribute("filter", filter.toString());
+
+    return obj;
+}
+
+void ValvesViewer::fromXmlObject(const XmlObject& xmlObject)
+{
+    if (xmlObject.getObjectName() == getName(ModuleId::VALVESVIEWER))
+    {
+        auto filter = Filter::fromString(xmlObject.getAttribute("filter"));
+        setFilter(filter);
+    }
+}
+
+void ValvesViewer::setupUi()
+{
+    outerLayout = new QHBoxLayout;
+    outerLayout->setContentsMargins(0, 0, 0, 0);
+    outerLayout->setSpacing(0);
+
+    for (auto labelText : ValvesList::valvesLabels)
+    {
+        QLabel* label = new QLabel;
+        label->setText(labelText);
+        label->setAlignment(Qt::AlignCenter);
+        label->setContentsMargins(4, 4, 4, 4);
+        outerLayout->addWidget(label);
+    }
+
+    setLayout(outerLayout);
+}
+
+void ValvesViewer::addCustomActionsToMenu()
+{
+    QAction* action = new QAction("Choose topic and field");
+    connect(action, &QAction::triggered, this,
+            &ValvesViewer::onConfigureClicked);
+
+    addActionToMenu(action);
+}
+
+void ValvesViewer::onConfigureClicked()
+{
+    FilterSelector::selectFilter(
+        filter, [this](const Filter& newFilter) { setFilter(newFilter); });
+}
+
+void ValvesViewer::setFilter(const Filter& newFilter)
+{
+    getCore()->getMessageBroker()->unsubscribe(filter, this);
+    getCore()->getMessageBroker()->subscribe(
+        newFilter, this,
+        [this](const Message& message, const Filter& filter)
+        { onMsgReceived(message); });
+    filter = newFilter;
+}
+
+void ValvesViewer::onMsgReceived(const Message& msg)
+{
+    // Couple the valves with their own state
+    QMap<ValvesList::Valve, uint64_t> map{
+        {ValvesList::Valve::FILLING,
+         msg.getField("filling_valve_state").getUnsignedInteger()},
+        {ValvesList::Valve::MAIN,
+         msg.getField("main_valve_state").getUnsignedInteger()},
+        {ValvesList::Valve::RELEASE,
+         msg.getField("release_valve_state").getUnsignedInteger()},
+        {ValvesList::Valve::VENTING,
+         msg.getField("venting_valve_state").getUnsignedInteger()}};
+
+    // Define the "active" and the "not active" look
+    QString baseStyle =
+        "border-bottom-width:1px;border-left-width:1px;border-top-width:"
+        "1px;border-radius:0;";
+    QString completedStyle = "background-color:green;" + baseStyle;
+    QString errorStyle     = "background-color:red;" + baseStyle;
+
+    // Iterate over the valves to assign them the correct look
+    for (auto i = map.cbegin(), end = map.cend(); i != end; i++)
+    {
+        if (i.value() == 1)
+        {
+            // The valve is opened
+            auto label =
+                outerLayout->itemAt(static_cast<int>(i.key()))->widget();
+            label->setStyleSheet(completedStyle);
+        }
+        else
+        {
+            // The valve is closed
+            auto label =
+                outerLayout->itemAt(static_cast<int>(i.key()))->widget();
+            label->setStyleSheet(errorStyle);
+        }
+    }
+}
diff --git a/src/shared/Modules/ValvesViewer/ValvesViewer.h b/src/shared/Modules/ValvesViewer/ValvesViewer.h
new file mode 100644
index 00000000..89fa9e7a
--- /dev/null
+++ b/src/shared/Modules/ValvesViewer/ValvesViewer.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of Skyward Hub.
+ *
+ * Skyward Hub 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, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Skyward Hub 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 for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Skyward Hub. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <Core/Message/Filter.h>
+#include <Core/Message/Message.h>
+#include <Modules/DefaultModule/DefaultModule.h>
+
+#include <QLabel>
+#include <QWidget>
+
+#include "ValvesList.h"
+
+class ValvesViewer : public DefaultModule
+{
+    Q_OBJECT
+
+public:
+    explicit ValvesViewer(QWidget* parent = nullptr);
+    ~ValvesViewer();
+
+    QWidget* toWidget() override;
+
+    XmlObject toXmlObject() override;
+    void fromXmlObject(const XmlObject& xmlObject) override;
+
+private:
+    void setupUi();
+    void addCustomActionsToMenu() override;
+    void onConfigureClicked();
+    void setFilter(const Filter& filter);
+    void onMsgReceived(const Message& msg);
+
+    QHBoxLayout* outerLayout;
+
+    Filter filter;
+    ValvesList::Valve currentState;
+};
-- 
GitLab