control: Add signal triggers with propertiesChanged signals

Add signal trigger support to the available triggers and include the
ability to subscribe and handle propertiesChanged signals.

Subscribing to a signal involves creating the signal's match string and
packaging the signal data for when the signal is received. Since a
single signal could be configured to be used across multiple dbus
objects and/or actions, the signal package is added in a way that each
event configured for the signal is processed from the signal received.

Handling the propertiesChanged signal involves filtering for the
configured dbus property, updating the cached value of the property, and
then allowing the actions for that signal to be run.

Change-Id: I04bc163b65115d9bac30315f690db5fefca5bde4
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/triggers/handlers.hpp b/control/json/triggers/handlers.hpp
new file mode 100644
index 0000000..2a52757
--- /dev/null
+++ b/control/json/triggers/handlers.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "../manager.hpp"
+
+#include <sdbusplus/message.hpp>
+
+#include <algorithm>
+#include <map>
+#include <tuple>
+#include <vector>
+
+namespace phosphor::fan::control::json::trigger::signal
+{
+
+using namespace sdbusplus::message;
+
+struct Handlers
+{
+
+  public:
+    /**
+     * @brief Processes a properties changed signal and updates the property's
+     * value in the manager's object cache
+     *
+     * @param[in] msg - The sdbusplus signal message
+     * @param[in] obj - Object data associated with the signal
+     * @param[in] mgr - Manager that stores the object cache
+     */
+    static bool propertiesChanged(message& msg, const SignalObject& obj,
+                                  Manager& mgr)
+    {
+        std::string intf;
+        msg.read(intf);
+        if (intf != std::get<Intf>(obj))
+        {
+            // Interface name does not match object's interface
+            return false;
+        }
+
+        std::map<std::string, PropertyVariantType> props;
+        msg.read(props);
+        auto itProp = props.find(std::get<Prop>(obj));
+        if (itProp == props.cend())
+        {
+            // Object's property not in dictionary of properties changed
+            return false;
+        }
+
+        mgr.setProperty(std::get<Path>(obj), std::get<Intf>(obj),
+                        std::get<Prop>(obj), itProp->second);
+        return true;
+    }
+};
+
+} // namespace phosphor::fan::control::json::trigger::signal