Evaluate conditions to determine zone

Change-Id: Idb825b27ecf98503ddc2405a0cafc30c644efc71
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/control/manager.cpp b/control/manager.cpp
index de9074c..c3c1226 100644
--- a/control/manager.cpp
+++ b/control/manager.cpp
@@ -17,6 +17,7 @@
 #include <phosphor-logging/log.hpp>
 #include <unistd.h>
 #include "manager.hpp"
+#include "utility.hpp"
 
 namespace phosphor
 {
@@ -32,6 +33,87 @@
 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
 constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target";
 
+constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
+constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
+constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
+
+
+/**
+ * Get the current value of the D-Bus property under the specified path
+ * and interface.
+ *
+ * @param[in] bus          - The D-Bus bus object
+ * @param[in] path         - The D-Bus path
+ * @param[in] interface    - The D-Bus interface
+ * @param[in] propertyName - The D-Bus property
+ * @param[out] value       - The D-Bus property's value
+ */
+template <typename T>
+void getProperty(sdbusplus::bus::bus& bus,
+                 const std::string& path,
+                 const std::string& interface,
+                 const std::string& propertyName,
+                 T& value)
+{
+    sdbusplus::message::variant<T> property;
+    std::string service = phosphor::fan::util::getService(path, interface, bus);
+
+    auto method = bus.new_method_call(service.c_str(),
+                                      path.c_str(),
+                                      PROPERTY_INTERFACE,
+                                      "Get");
+
+    method.append(interface, propertyName);
+    auto reply = bus.call(method);
+
+    if (reply.is_method_error())
+    {
+        throw std::runtime_error(
+            "Error in call response for retrieving property");
+    }
+    reply.read(property);
+    value = sdbusplus::message::variant_ns::get<T>(property);
+}
+
+
+/**
+ * Check if a condition is true. Conditions are used to determine
+ * which fan zone to use.
+ *
+ * @param[in] bus       - The D-Bus bus object
+ * @param[in] condition - The condition to check if true
+ * @return result       - True if the condition is true
+ */
+bool checkCondition(sdbusplus::bus::bus& bus, const auto& c)
+{
+    auto& type = std::get<conditionTypePos>(c);
+    auto& properties = std::get<conditionPropertyListPos>(c);
+
+    for (auto& p : properties)
+    {
+        bool value = std::get<propertyValuePos>(p);
+        bool propertyValue;
+
+        // TODO openbmc/openbmc#1769: Support more types than just getProperty.
+        if (type.compare("getProperty") == 0)
+        {
+            getProperty(bus,
+                        std::get<propertyPathPos>(p),
+                        std::get<propertyInterfacePos>(p),
+                        std::get<propertyNamePos>(p),
+                        propertyValue);
+
+            if (value != propertyValue)
+            {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+
 //Note: Future code will check 'mode' before starting control algorithm
 Manager::Manager(sdbusplus::bus::bus& bus,
                  Mode mode) :
@@ -46,12 +128,10 @@
         auto& conditions = std::get<conditionListPos>(group);
 
         if (std::all_of(conditions.begin(), conditions.end(),
-                        [](const auto& c)
-                        {
-                            //TODO: openbmc/openbmc#1500
-                            //Still need to actually evaluate the conditions
-                            return true;
-                        }))
+                        [&bus](const auto& condition)
+        {
+            return checkCondition(bus, condition);
+        }))
         {
             //Create a Zone object for each zone in this group
             auto& zones = std::get<zoneListPos>(group);
@@ -71,7 +151,7 @@
 
 void Manager::doInit()
 {
-    for (auto& z: _zones)
+    for (auto& z : _zones)
     {
         z.second->setFullSpeed();
     }
@@ -89,9 +169,9 @@
 void Manager::startFanControlReadyTarget()
 {
     auto method = _bus.new_method_call(SYSTEMD_SERVICE,
-            SYSTEMD_OBJ_PATH,
-            SYSTEMD_INTERFACE,
-            "StartUnit");
+                                       SYSTEMD_OBJ_PATH,
+                                       SYSTEMD_INTERFACE,
+                                       "StartUnit");
 
     method.append(FAN_CONTROL_READY_TARGET);
     method.append("replace");
@@ -105,6 +185,6 @@
     }
 }
 
-}
-}
-}
+} // namespace control
+} // namespace fan
+} // namespace phosphor
diff --git a/control/types.hpp b/control/types.hpp
index a9508eb..2b7509c 100644
--- a/control/types.hpp
+++ b/control/types.hpp
@@ -12,8 +12,21 @@
 
 class Zone;
 
-//Placeholder. Conditions are completely TBD.
-using Condition = bool;
+constexpr auto propertyNamePos = 0;
+constexpr auto propertyInterfacePos = 1;
+constexpr auto propertyPathPos = 2;
+constexpr auto propertyValuePos = 3;
+
+// TODO openbmc/openbmc#1769: Support more property types.
+using ConditionProperty = std::tuple<std::string,
+                          std::string,
+                          std::string,
+                          bool>;
+
+constexpr auto conditionTypePos = 0;
+constexpr auto conditionPropertyListPos = 1;
+using Condition = std::tuple<std::string,
+                             std::vector<ConditionProperty>>;
 
 constexpr auto fanNamePos = 0;
 constexpr auto sensorListPos = 1;