From e2083224f106ff6983bb1e92bb90313701a91b9b Mon Sep 17 00:00:00 2001
From: Don Gagne <don@thegagnes.com>
Date: Tue, 3 Dec 2024 11:11:55 -0800
Subject: [PATCH] Add new RPM vehicle FactGroup

---
 qgroundcontrol.qrc                            |  1 +
 src/Vehicle/FactGroups/CMakeLists.txt         |  2 +
 src/Vehicle/FactGroups/RPMFact.json           | 35 +++++++++++
 src/Vehicle/FactGroups/VehicleRPMFactGroup.cc | 61 +++++++++++++++++++
 src/Vehicle/FactGroups/VehicleRPMFactGroup.h  | 45 ++++++++++++++
 src/Vehicle/Vehicle.cc                        |  2 +
 src/Vehicle/Vehicle.h                         |  4 ++
 7 files changed, 150 insertions(+)
 create mode 100644 src/Vehicle/FactGroups/RPMFact.json
 create mode 100644 src/Vehicle/FactGroups/VehicleRPMFactGroup.cc
 create mode 100644 src/Vehicle/FactGroups/VehicleRPMFactGroup.h

diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index bf22c447445..de282e5fe87 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -406,6 +406,7 @@
         <file alias="Vehicle/SetpointFact.json">src/Vehicle/FactGroups/SetpointFact.json</file>
         <file alias="Vehicle/LocalPositionFact.json">src/Vehicle/FactGroups/LocalPositionFact.json</file>
         <file alias="Vehicle/LocalPositionSetpointFact.json">src/Vehicle/FactGroups/LocalPositionFact.json</file>
+        <file alias="Vehicle/RPMFact.json">src/Vehicle/FactGroups/RPMFact.json</file>
         <file alias="Vehicle/SubmarineFact.json">src/Vehicle/FactGroups/SubmarineFact.json</file>
         <file alias="Vehicle/TemperatureFact.json">src/Vehicle/FactGroups/TemperatureFact.json</file>
         <file alias="Vehicle/TerrainFactGroup.json">src/Vehicle/FactGroups/TerrainFactGroup.json</file>
diff --git a/src/Vehicle/FactGroups/CMakeLists.txt b/src/Vehicle/FactGroups/CMakeLists.txt
index dfcf902457e..4c8ecb9625f 100644
--- a/src/Vehicle/FactGroups/CMakeLists.txt
+++ b/src/Vehicle/FactGroups/CMakeLists.txt
@@ -27,6 +27,8 @@ qt_add_library(VehicleFactGroups STATIC
     VehicleLocalPositionFactGroup.h
     VehicleLocalPositionSetpointFactGroup.cc
     VehicleLocalPositionSetpointFactGroup.h
+    VehicleRPMFactGroup.cc
+    VehicleRPMFactGroup.h
     VehicleSetpointFactGroup.cc
     VehicleSetpointFactGroup.h
     VehicleTemperatureFactGroup.cc
diff --git a/src/Vehicle/FactGroups/RPMFact.json b/src/Vehicle/FactGroups/RPMFact.json
new file mode 100644
index 00000000000..ae5aeab6a35
--- /dev/null
+++ b/src/Vehicle/FactGroups/RPMFact.json
@@ -0,0 +1,35 @@
+{
+    "version":      1,
+    "fileType":  "FactMetaData",
+    "QGC.MetaData.Facts":
+    [
+        {
+            "name":             "rpm1",
+            "shortDesc":        "RPM 1",
+            "type":             "double",
+            "decimalPlaces":    2,
+            "units":            "rpm"
+        },
+        {
+            "name":             "rpm2",
+            "shortDesc":        "RPM 2",
+            "type":             "double",
+            "decimalPlaces":    2,
+            "units":            "rpm"
+        },
+        {
+            "name":             "rpm3",
+            "shortDesc":        "RPM 3",
+            "type":             "double",
+            "decimalPlaces":    2,
+            "units":            "rpm"
+        },
+        {
+            "name":             "rpm4",
+            "shortDesc":        "RPM 4",
+            "type":             "double",
+            "decimalPlaces":    2,
+            "units":            "rpm"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/Vehicle/FactGroups/VehicleRPMFactGroup.cc b/src/Vehicle/FactGroups/VehicleRPMFactGroup.cc
new file mode 100644
index 00000000000..67f6c6ac435
--- /dev/null
+++ b/src/Vehicle/FactGroups/VehicleRPMFactGroup.cc
@@ -0,0 +1,61 @@
+/****************************************************************************
+ *
+ * (c) 2009-2023 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#include "VehicleSetpointFactGroup.h"
+#include "Vehicle.h"
+
+const char* VehicleRPMFactGroup::_rpm1FactName = "rpm1";
+const char* VehicleRPMFactGroup::_rpm2FactName = "rpm2";
+const char* VehicleRPMFactGroup::_rpm3FactName = "rpm3";
+const char* VehicleRPMFactGroup::_rpm4FactName = "rpm4";
+
+VehicleRPMFactGroup::VehicleRPMFactGroup(QObject* parent)
+    : FactGroup(1000, ":/json/Vehicle/RPMFact.json", parent)
+    , _rpm1Fact(0, _rpm1FactName, FactMetaData::valueTypeDouble)
+    , _rpm2Fact(0, _rpm2FactName, FactMetaData::valueTypeDouble)
+    , _rpm3Fact(0, _rpm3FactName, FactMetaData::valueTypeDouble)
+    , _rpm4Fact(0, _rpm4FactName, FactMetaData::valueTypeDouble)
+{
+    _addFact(&_rpm1Fact, _rpm1FactName);
+    _addFact(&_rpm2Fact, _rpm2FactName);
+    _addFact(&_rpm3Fact, _rpm3FactName);
+    _addFact(&_rpm4Fact, _rpm4FactName);
+
+    // Start out as not available "--.--"
+    _rpm1Fact.setRawValue(qQNaN());
+    _rpm2Fact.setRawValue(qQNaN());
+    _rpm3Fact.setRawValue(qQNaN());
+    _rpm4Fact.setRawValue(qQNaN());
+}
+
+void VehicleRPMFactGroup::handleMessage(Vehicle* /* vehicle */, mavlink_message_t& message)
+{
+    if (message.msgid == MAVLINK_MSG_ID_RAW_RPM) {
+        mavlink_raw_rpm_t raw_rpm;
+        mavlink_msg_raw_rpm_decode(&message, &raw_rpm);
+        switch (raw_rpm.index) {
+            case 0:
+                rpm1()->setRawValue(raw_rpm.frequency);
+                break;
+            case 1:
+                rpm2()->setRawValue(raw_rpm.frequency);
+                break;
+            case 2: 
+                rpm3()->setRawValue(raw_rpm.frequency);
+                break;
+            case 3: 
+                rpm4()->setRawValue(raw_rpm.frequency);
+                break;
+            default:
+                break;
+
+        }
+        _setTelemetryAvailable(true);
+    }
+}
diff --git a/src/Vehicle/FactGroups/VehicleRPMFactGroup.h b/src/Vehicle/FactGroups/VehicleRPMFactGroup.h
new file mode 100644
index 00000000000..be1bd2998ec
--- /dev/null
+++ b/src/Vehicle/FactGroups/VehicleRPMFactGroup.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+ *
+ * (c) 2009-2023 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include "FactGroup.h"
+#include "QGCMAVLink.h"
+
+class VehicleRPMFactGroup : public FactGroup
+{
+    Q_OBJECT
+
+public:
+    VehicleRPMFactGroup(QObject* parent = nullptr);
+
+    Q_PROPERTY(Fact* rpm1 READ rpm1 CONSTANT)
+    Q_PROPERTY(Fact* rpm2 READ rpm2 CONSTANT)
+    Q_PROPERTY(Fact* rpm3 READ rpm3 CONSTANT)
+    Q_PROPERTY(Fact* rpm4 READ rpm4 CONSTANT)
+
+    Fact* rpm1 () { return &_rpm1Fact; }
+    Fact* rpm2 () { return &_rpm2Fact; }
+    Fact* rpm3 () { return &_rpm3Fact; }
+    Fact* rpm4 () { return &_rpm4Fact; }
+
+    // Overrides from FactGroup
+    void handleMessage(Vehicle* vehicle, mavlink_message_t& message) override;
+
+    static const char* _rpm1FactName;
+    static const char* _rpm2FactName;
+    static const char* _rpm3FactName;
+    static const char* _rpm4FactName;
+
+private:
+    Fact _rpm1Fact;
+    Fact _rpm2Fact;
+    Fact _rpm3Fact;
+    Fact _rpm4Fact;
+};
diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc
index 376ab0eaba0..22493407f0d 100644
--- a/src/Vehicle/Vehicle.cc
+++ b/src/Vehicle/Vehicle.cc
@@ -108,6 +108,7 @@ Vehicle::Vehicle(LinkInterface*             link,
     , _hygrometerFactGroup          (this)
     , _generatorFactGroup           (this)
     , _efiFactGroup                 (this)
+    , _rpmFactGroup                 (this)
     , _terrainFactGroup             (this)
     , _terrainProtocolHandler       (new TerrainProtocolHandler(this, &_terrainFactGroup, this))
 {
@@ -330,6 +331,7 @@ void Vehicle::_commonInit()
     _addFactGroup(&_hygrometerFactGroup,        _hygrometerFactGroupName);
     _addFactGroup(&_generatorFactGroup,         _generatorFactGroupName);
     _addFactGroup(&_efiFactGroup,               _efiFactGroupName);
+    _addFactGroup(&_rpmFactGroup,               _rpmFactGroupName);
     _addFactGroup(&_terrainFactGroup,           _terrainFactGroupName);
 
     // Add firmware-specific fact groups, if provided
diff --git a/src/Vehicle/Vehicle.h b/src/Vehicle/Vehicle.h
index c0a13a2bdde..b8d52ac2e03 100644
--- a/src/Vehicle/Vehicle.h
+++ b/src/Vehicle/Vehicle.h
@@ -39,6 +39,7 @@
 #include "VehicleHygrometerFactGroup.h"
 #include "VehicleLocalPositionFactGroup.h"
 #include "VehicleLocalPositionSetpointFactGroup.h"
+#include "VehicleRPMFactGroup.h"
 #include "VehicleSetpointFactGroup.h"
 #include "VehicleTemperatureFactGroup.h"
 #include "VehicleVibrationFactGroup.h"
@@ -601,6 +602,7 @@ class Vehicle : public VehicleFactGroup
     FactGroup* hygrometerFactGroup          () { return &_hygrometerFactGroup; }
     FactGroup* generatorFactGroup           () { return &_generatorFactGroup; }
     FactGroup* efiFactGroup                 () { return &_efiFactGroup; }
+    FactGroup* rpmFactGroup                 () { return &_rpmFactGroup; }
     QmlObjectListModel* batteries           () { return &_batteryFactGroupListModel; }
 
     MissionManager*                 missionManager      () { return _missionManager; }
@@ -1229,6 +1231,7 @@ private slots:
     const QString _hygrometerFactGroupName =         QStringLiteral("hygrometer");
     const QString _generatorFactGroupName =          QStringLiteral("generator");
     const QString _efiFactGroupName =                QStringLiteral("efi");
+    const QString _rpmFactGroupName =                QStringLiteral("rpm");
 
     VehicleFactGroup*               _vehicleFactGroup;
     VehicleGPSFactGroup             _gpsFactGroup;
@@ -1246,6 +1249,7 @@ private slots:
     VehicleHygrometerFactGroup      _hygrometerFactGroup;
     VehicleGeneratorFactGroup       _generatorFactGroup;
     VehicleEFIFactGroup             _efiFactGroup;
+    VehicleRPMFactGroup             _rpmFactGroup;
     TerrainFactGroup                _terrainFactGroup;
     QmlObjectListModel              _batteryFactGroupListModel;