Add support for dbus parameter

Added support for parameter type dbus sensor and utility functions
to read dbus sensor value.

Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Change-Id: I04db0016f312edea095442a693500c3b4e571d6c
diff --git a/dbusSensor.hpp b/dbusSensor.hpp
new file mode 100644
index 0000000..8ab17a2
--- /dev/null
+++ b/dbusSensor.hpp
@@ -0,0 +1,38 @@
+#include "dbusUtils.hpp"
+
+#include <sdbusplus/bus.hpp>
+
+const char* sensorIntf = "xyz.openbmc_project.Sensor.Value";
+
+class DbusSensor
+{
+  public:
+    DbusSensor() = delete;
+    virtual ~DbusSensor() = default;
+
+    /** @brief Constructs DbusSensor
+     *
+     * @param[in] bus     - Handle to system dbus
+     * @param[in] path    - The Dbus path of sensor
+     */
+    DbusSensor(sdbusplus::bus::bus& bus, const std::string& path) :
+        bus(bus), path(path)
+    {
+        servName = getService(bus, path, sensorIntf);
+    }
+
+    /** @brief Get sensor value property from D-bus interface */
+    double getSensorValue()
+    {
+        return getDbusProperty<double>(bus, servName, path, sensorIntf,
+                                       "Value");
+    }
+
+  private:
+    /** @brief sdbusplus bus client connection. */
+    sdbusplus::bus::bus& bus;
+    /** @brief complete path for sensor */
+    std::string path;
+    /** @brief service name for the sensor daemon */
+    std::string servName;
+};
diff --git a/dbusUtils.hpp b/dbusUtils.hpp
new file mode 100644
index 0000000..a12a21d
--- /dev/null
+++ b/dbusUtils.hpp
@@ -0,0 +1,84 @@
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+const char* propIntf = "org.freedesktop.DBus.Properties";
+const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
+const char* mapperPath = "/xyz/openbmc_project/object_mapper";
+const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
+
+const char* methodGetObject = "GetObject";
+const char* methodGet = "Get";
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+using Value = std::variant<int64_t, double, std::string, bool>;
+
+std::string getService(sdbusplus::bus::bus& bus, const std::string& path,
+                       const char* intf)
+{
+    /* Get mapper object for sensor path */
+    auto mapper = bus.new_method_call(mapperBusName, mapperPath, mapperIntf,
+                                      methodGetObject);
+
+    mapper.append(path.c_str());
+    mapper.append(std::vector<std::string>({intf}));
+
+    std::unordered_map<std::string, std::vector<std::string>> resp;
+
+    try
+    {
+        auto msg = bus.call(mapper);
+
+        msg.read(resp);
+        if (msg.is_method_error())
+        {
+            log<level::ERR>("Error in mapper call");
+            elog<InternalFailure>();
+        }
+    }
+    catch (const sdbusplus::exception::SdBusError& ex)
+    {
+        log<level::ERR>("ObjectMapper call failure",
+                        entry("WHAT=%s", ex.what()));
+        throw;
+    }
+
+    if (resp.begin() == resp.end())
+    {
+        throw std::runtime_error("Unable to find Object: " + path);
+    }
+
+    return resp.begin()->first;
+}
+
+template <typename T>
+
+T getDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
+                  const std::string& path, const std::string& intf,
+                  const std::string& property)
+{
+
+    Value value;
+
+    auto method =
+        bus.new_method_call(service.c_str(), path.c_str(), propIntf, methodGet);
+
+    method.append(intf, property);
+
+    auto msg = bus.call(method);
+
+    if (msg.is_method_error())
+    {
+        log<level::ERR>("Failed to get property",
+                        entry("PROPERTY=%s", property.c_str()),
+                        entry("PATH=%s", path.c_str()),
+                        entry("INTERFACE=%s", intf.c_str()));
+        elog<InternalFailure>();
+    }
+
+    msg.read(value);
+
+    return std::get<T>(value);
+}
diff --git a/virtualSensor.cpp b/virtualSensor.cpp
index ef8543f..501d9cd 100644
--- a/virtualSensor.cpp
+++ b/virtualSensor.cpp
@@ -39,6 +39,9 @@
         case constParam:
             return value;
             break;
+        case dbusParam:
+            return dbusSensor->getSensorValue();
+            break;
         default:
             throw std::invalid_argument("param type not supported");
     }
@@ -92,7 +95,30 @@
         }
     }
 
-    /* TODO: Check for dbus parameter */
+    /* Check for dbus parameter */
+    auto dbusParams = params.value("DbusParam", empty);
+    if (!dbusParams.empty())
+    {
+        for (auto& j : dbusParams)
+        {
+            /* Get parameter dbus sensor descriptor */
+            auto desc = j.value("Desc", empty);
+            if ((!desc.empty()) && (j.find("ParamName") != j.end()))
+            {
+                std::string sensorType = desc.value("SensorType", "");
+                std::string name = desc.value("Name", "");
+
+                if (!sensorType.empty() && !name.empty())
+                {
+                    std::string objPath(sensorDbusPath);
+                    objPath += sensorType + "/" + name;
+
+                    auto paramPtr = std::make_unique<SensorParam>(bus, objPath);
+                    paramMap.emplace(j["ParamName"], std::move(paramPtr));
+                }
+            }
+        }
+    }
 
     /* Print all parameters for debug purpose only */
     if (DEBUG)
diff --git a/virtualSensor.hpp b/virtualSensor.hpp
index a49c94f..6b11eb4 100644
--- a/virtualSensor.hpp
+++ b/virtualSensor.hpp
@@ -1,3 +1,5 @@
+#include "dbusSensor.hpp"
+
 #include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
 #include <xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp>
@@ -44,11 +46,22 @@
     explicit SensorParam(double value) : value(value), paramType(constParam)
     {}
 
+    /** @brief Constructs SensorParam (type = dbusParam)
+     *
+     * @param[in] bus     - Handle to system dbus
+     * @param[in] path    - The Dbus path of sensor
+     */
+    SensorParam(sdbusplus::bus::bus& bus, std::string path) :
+        dbusSensor(std::make_unique<DbusSensor>(bus, path)),
+        paramType(dbusParam)
+    {}
+
     /** @brief Get sensor value property from D-bus interface */
     double getParamValue();
 
   private:
-    double value;
+    std::unique_ptr<DbusSensor> dbusSensor = nullptr;
+    double value = 0;
     ParamType paramType;
 };