Enable tach signal handler

Register and handle tach change signals for each tach sensor.
Inventory would be updated when all tach sensors for a specific fan
enclosure have a tach value of zero.

Change-Id: Idd3f53c29c68c6171d858e616fbfe868f30a4ea9
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/fan_enclosure.cpp b/fan_enclosure.cpp
index 46efeb5..b02d6e1 100644
--- a/fan_enclosure.cpp
+++ b/fan_enclosure.cpp
@@ -1,3 +1,4 @@
+#include <algorithm>
 #include "fan_enclosure.hpp"
 
 
@@ -13,6 +14,19 @@
     //TODO Add this fan to inventory
 }
 
+void FanEnclosure::updInventory()
+{
+    auto presPred = [](auto const& s) {return s->isPresent();};
+    // Determine if all sensors show fan is not present
+    auto isPresent = std::any_of(FanEnclosure::sensors.begin(),
+                                 FanEnclosure::sensors.end(),
+                                 presPred);
+    if (!isPresent)
+    {
+        //TODO Update inventory for this fan
+    }
+}
+
 void FanEnclosure::addSensor(
     std::unique_ptr<Sensor>&& sensor)
 {
diff --git a/fan_enclosure.hpp b/fan_enclosure.hpp
index 0b96bfc..5c6a040 100644
--- a/fan_enclosure.hpp
+++ b/fan_enclosure.hpp
@@ -32,6 +32,7 @@
             addInventory();
         }
 
+        void updInventory();
         void addSensor(
             std::unique_ptr<Sensor>&& sensor);
 
diff --git a/tach_sensor.cpp b/tach_sensor.cpp
index 987e390..91e249d 100644
--- a/tach_sensor.cpp
+++ b/tach_sensor.cpp
@@ -1,4 +1,6 @@
+#include <sdbusplus/exception.hpp>
 #include "tach_sensor.hpp"
+#include "fan_enclosure.hpp"
 
 
 namespace phosphor
@@ -13,6 +15,40 @@
     return (tach != 0);
 }
 
+// Tach signal callback handler
+int TachSensor::handleTachChangeSignal(sd_bus_message* msg,
+                                       void* usrData,
+                                       sd_bus_error* err)
+{
+    auto sdbpMsg = sdbusplus::message::message(msg);
+    static_cast<TachSensor*>(usrData)->handleTachChange(sdbpMsg, err);
+    return 0;
+}
+
+void TachSensor::handleTachChange(sdbusplus::message::message& sdbpMsg,
+                                  sd_bus_error* err)
+{
+    std::string msgSensor;
+    std::map<std::string, sdbusplus::message::variant<int64_t>> msgData;
+    sdbpMsg.read(msgSensor, msgData);
+
+    // TODO openbmc/phosphor-fan-presence#5
+    //      Update to use 'arg0namespace' match option to reduce dbus traffic
+    // Find interface with value property
+    if (msgSensor.compare("xyz.openbmc_project.Sensor.Value") == 0)
+    {
+        // Find the 'Value' property containing tach
+        auto valPropMap = msgData.find("Value");
+        if (valPropMap != msgData.end())
+        {
+            tach = sdbusplus::message::variant_ns::get<int64_t>(
+                valPropMap->second);
+        }
+    }
+    // Update inventory according to latest tach reported
+    fanEnc.updInventory();
+}
+
 } // namespace presence
 } // namespace fan
 } // namespace phosphor
diff --git a/tach_sensor.hpp b/tach_sensor.hpp
index 24ee453..b9ac9b3 100644
--- a/tach_sensor.hpp
+++ b/tach_sensor.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
 #include "sensor_base.hpp"
 
 
@@ -21,10 +22,16 @@
         TachSensor& operator=(TachSensor&&) = delete;
         ~TachSensor() = default;
 
-        TachSensor(sdbusplus::bus::bus& bus,
-                   const std::string& id,
-                   FanEnclosure& fanEnc) : Sensor(id, fanEnc),
-                       bus(bus)
+        TachSensor(
+            sdbusplus::bus::bus& bus,
+            const std::string& id,
+            FanEnclosure& fanEnc) :
+                Sensor(id, fanEnc),
+                bus(bus),
+                tachSignal(bus,
+                           match(id).c_str(),
+                           handleTachChangeSignal,
+                           this)
         {
             // Nothing to do here
         }
@@ -33,8 +40,25 @@
 
     private:
         sdbusplus::bus::bus& bus;
+        sdbusplus::server::match::match tachSignal;
         int64_t tach = 0;
 
+        static std::string match(std::string id)
+        {
+            return std::string("type='signal',"
+                               "interface='org.freedesktop.DBus.Properties',"
+                               "member='PropertiesChanged',"
+                               "path='/xyz/openbmc_project/sensors/fan_tach/" +
+                               id + "'");
+        }
+        // Tach signal callback handler
+        static int handleTachChangeSignal(sd_bus_message* msg,
+                                          void* data,
+                                          sd_bus_error* err);
+
+        void handleTachChange(sdbusplus::message::message& msg,
+                              sd_bus_error* err);
+
 };
 
 } // namespace presence