dbuspassive: allow scaling

For tachs it is beneficial to deal in percent so that
multiple controllers can be used with different fan
types without having to recalculate. This starts using
the unused min and max fields to be able to scale readings.
Since max and min are commonly on the value interface, the
special value of <int64_t>::lowest() allows these to be gathered
from dbus instead of having to enter them manually.

Tested-by: Moved pid control to percent and printed
outputs

Change-Id: I9496eb92a18b68a7cd7f034d41d40ef5175c6974
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/conf.hpp b/conf.hpp
index cfea278..8a6170d 100644
--- a/conf.hpp
+++ b/conf.hpp
@@ -7,6 +7,11 @@
 #include <string>
 #include <vector>
 
+namespace conf
+{
+constexpr int64_t inheritValueFromDbus = std::numeric_limits<int64_t>::lowest();
+} // namespace conf
+
 /*
  * General sensor structure used for configuration.
  */
diff --git a/dbus/dbusconfiguration.cpp b/dbus/dbusconfiguration.cpp
index b449490..06bcdcc 100644
--- a/dbus/dbusconfiguration.cpp
+++ b/dbus/dbusconfiguration.cpp
@@ -366,6 +366,11 @@
                         {
                             config.timeout = 0;
                         }
+                        else if (config.type == "fan")
+                        {
+                            config.max = conf::inheritValueFromDbus;
+                            config.min = conf::inheritValueFromDbus;
+                        }
                     }
                     else if (sensorPathIfacePair.second == pwmInterface)
                     {
diff --git a/dbus/dbuspassive.cpp b/dbus/dbuspassive.cpp
index 6d8aa03..206adbe 100644
--- a/dbus/dbuspassive.cpp
+++ b/dbus/dbuspassive.cpp
@@ -27,7 +27,7 @@
 
 std::unique_ptr<ReadInterface> DbusPassive::createDbusPassive(
     sdbusplus::bus::bus& bus, const std::string& type, const std::string& id,
-    DbusHelperInterface* helper)
+    DbusHelperInterface* helper, const SensorConfig* info)
 {
     if (helper == nullptr)
     {
@@ -58,6 +58,15 @@
     {
         return nullptr;
     }
+    if (info->max != conf::inheritValueFromDbus)
+    {
+        settings.max = info->max;
+    }
+
+    if (info->max != conf::inheritValueFromDbus)
+    {
+        settings.min = info->min;
+    }
 
     return std::make_unique<DbusPassive>(bus, type, id, helper, settings,
                                          failed);
@@ -72,6 +81,8 @@
 {
     _scale = settings.scale;
     _value = settings.value * pow(10, _scale);
+    _min = settings.min * pow(10, _scale);
+    _max = settings.max * pow(10, _scale);
     _updated = std::chrono::high_resolution_clock::now();
 }
 
@@ -112,6 +123,16 @@
     return _id;
 }
 
+double DbusPassive::getMax(void)
+{
+    return _max;
+}
+
+double DbusPassive::getMin(void)
+{
+    return _min;
+}
+
 int handleSensorValue(sdbusplus::message::message& msg, DbusPassive* owner)
 {
     std::string msgSensor;
@@ -129,6 +150,8 @@
 
             value *= std::pow(10, owner->getScale());
 
+            scaleSensorReading(owner->getMin(), owner->getMax(), value);
+
             owner->setValue(value);
         }
     }
diff --git a/dbus/dbuspassive.hpp b/dbus/dbuspassive.hpp
index 5dbd3c3..fa9dab7 100644
--- a/dbus/dbuspassive.hpp
+++ b/dbus/dbuspassive.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "conf.hpp"
 #include "dbus/util.hpp"
 #include "interfaces.hpp"
 
@@ -35,7 +36,8 @@
   public:
     static std::unique_ptr<ReadInterface>
         createDbusPassive(sdbusplus::bus::bus& bus, const std::string& type,
-                          const std::string& id, DbusHelperInterface* helper);
+                          const std::string& id, DbusHelperInterface* helper,
+                          const SensorConfig* info);
 
     DbusPassive(sdbusplus::bus::bus& bus, const std::string& type,
                 const std::string& id, DbusHelperInterface* helper,
@@ -48,6 +50,8 @@
     void setFailed(bool value);
     int64_t getScale(void);
     std::string getID(void);
+    double getMax(void);
+    double getMin(void);
 
   private:
     sdbusplus::bus::bus& _bus;
@@ -58,6 +62,8 @@
 
     std::mutex _lock;
     double _value = 0;
+    double _max = 0;
+    double _min = 0;
     bool _failed = false;
     /* The last time the value was refreshed, not necessarily changed. */
     std::chrono::high_resolution_clock::time_point _updated;
diff --git a/dbus/util.cpp b/dbus/util.cpp
index 5a572d0..b5b22f4 100644
--- a/dbus/util.cpp
+++ b/dbus/util.cpp
@@ -88,13 +88,23 @@
         prop->unit = std::get<std::string>(findUnit->second);
     }
     auto findScale = propMap.find("Scale");
+    auto findMax = propMap.find("MaxValue");
+    auto findMin = propMap.find("MinValue");
+
+    prop->min = 0;
+    prop->max = 0;
+    prop->scale = 0;
     if (findScale != propMap.end())
     {
         prop->scale = std::get<int64_t>(findScale->second);
     }
-    else
+    if (findMax != propMap.end())
     {
-        prop->scale = 0;
+        prop->max = std::visit(VariantToDoubleVisitor(), findMax->second);
+    }
+    if (findMin != propMap.end())
+    {
+        prop->min = std::visit(VariantToDoubleVisitor(), findMin->second);
     }
 
     prop->value = std::visit(VariantToDoubleVisitor(), propMap["Value"]);
@@ -174,3 +184,12 @@
     static std::set<std::string> valid = {"fan", "temp"};
     return (valid.find(type) != valid.end());
 }
+
+void scaleSensorReading(const double min, const double max, double& value)
+{
+    if (max <= 0)
+    {
+        return;
+    }
+    value /= (max - min);
+}
\ No newline at end of file
diff --git a/dbus/util.hpp b/dbus/util.hpp
index 719bb1d..69a8112 100644
--- a/dbus/util.hpp
+++ b/dbus/util.hpp
@@ -7,6 +7,8 @@
 {
     int64_t scale;
     double value;
+    double min;
+    double max;
     std::string unit;
 };
 
@@ -83,6 +85,7 @@
 
 std::string getSensorPath(const std::string& type, const std::string& id);
 std::string getMatch(const std::string& type, const std::string& id);
+void scaleSensorReading(const double min, const double max, double& value);
 bool validType(const std::string& type);
 
 struct VariantToDoubleVisitor
diff --git a/sensors/builder.cpp b/sensors/builder.cpp
index 4ba1837..adffd81 100644
--- a/sensors/builder.cpp
+++ b/sensors/builder.cpp
@@ -67,8 +67,8 @@
         switch (rtype)
         {
             case IOInterfaceType::DBUSPASSIVE:
-                ri = DbusPassive::createDbusPassive(passiveListeningBus,
-                                                    info->type, name, &helper);
+                ri = DbusPassive::createDbusPassive(
+                    passiveListeningBus, info->type, name, &helper, info);
                 if (ri == nullptr)
                 {
                     throw SensorBuildException(
diff --git a/test/dbus_passive_unittest.cpp b/test/dbus_passive_unittest.cpp
index 81238a5..92a30af 100644
--- a/test/dbus_passive_unittest.cpp
+++ b/test/dbus_passive_unittest.cpp
@@ -1,3 +1,4 @@
+#include "conf.hpp"
 #include "dbus/dbuspassive.hpp"
 #include "test/dbushelper_mock.hpp"
 
@@ -28,9 +29,10 @@
     std::string id = "id";
 
     DbusHelperMock helper;
+    auto info = SensorConfig();
 
     std::unique_ptr<ReadInterface> ri =
-        DbusPassive::createDbusPassive(bus_mock, type, id, &helper);
+        DbusPassive::createDbusPassive(bus_mock, type, id, &helper, &info);
 
     EXPECT_EQ(ri, nullptr);
 }
@@ -74,7 +76,8 @@
         EXPECT_CALL(helper, thresholdsAsserted(_, StrEq("asdf"), StrEq(path)))
             .WillOnce(Return(false));
 
-        ri = DbusPassive::createDbusPassive(bus_mock, type, id, &helper);
+        auto info = SensorConfig();
+        ri = DbusPassive::createDbusPassive(bus_mock, type, id, &helper, &info);
         passive = reinterpret_cast<DbusPassive*>(ri.get());
         EXPECT_FALSE(passive == nullptr);
     }