Add pgood signal handler.

Pgood indicate if host is on, which will be used to handle the time
mode/owner changes.

Change-Id: I7be4f7300aca3d1adc118eb3eb447c1e3734c89f
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/manager.cpp b/manager.cpp
index c4732f4..5a3d928 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -22,6 +22,17 @@
     rules::path("/org/openbmc/settings/host0") +
     rules::interface("org.freedesktop.DBus.Properties");
 
+const auto MATCH_PGOOD_CHANGE =
+    rules::type::signal() +
+    rules::member("PropertiesChanged") +
+    rules::path("/org/openbmc/control/power0") +
+    rules::interface("org.freedesktop.DBus.Properties");
+
+// TODO: consider put the get properties related functions into a common place
+constexpr auto POWER_SERVICE = "org.openbmc.control.Power";
+constexpr auto POWER_PATH = "/org/openbmc/control/power0";
+constexpr auto POWER_INTERFACE = POWER_SERVICE;
+constexpr auto PGOOD_STR = "pgood";
 }
 
 namespace phosphor
@@ -44,10 +55,12 @@
 
 Manager::Manager(sdbusplus::bus::bus& bus)
     : bus(bus),
-      propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this)
+      propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this),
+      pgoodChangeMatch(bus, MATCH_PGOOD_CHANGE, onPgoodChanged, this)
 {
     setCurrentTimeMode(getSettings(PROPERTY_TIME_MODE));
     setCurrentTimeOwner(getSettings(PROPERTY_TIME_OWNER));
+    checkHostOn();
 }
 
 void Manager::addListener(PropertyChangeListner* listener)
@@ -59,12 +72,30 @@
     listeners.insert(listener);
 }
 
+void Manager::checkHostOn()
+{
+    sdbusplus::message::variant<int> pgood = 0;
+    auto method = bus.new_method_call(POWER_SERVICE,
+                                      POWER_PATH,
+                                      PROPERTY_INTERFACE,
+                                      METHOD_GET);
+    method.append(PROPERTY_INTERFACE, PGOOD_STR);
+    auto reply = bus.call(method);
+    if (reply)
+    {
+        reply.read(pgood);
+    }
+
+    hostOn = static_cast<bool>(pgood.get<int>());
+}
+
 void Manager::onPropertyChanged(const std::string& key,
                                 const std::string& value)
 {
     // TODO: Check pgood
     // If it's off, notify listners;
-    // If it's on, hold the values and store in persistent storage.
+    // If it's on, hold the values and store in persistent storage
+    // as requested time mode/owner.
     // And when pgood turns back to off, notify the listners.
 
     // TODO: Check dhcp_ntp
@@ -92,7 +123,7 @@
                                sd_bus_error* retError)
 {
     using properties = std::map < std::string,
-          sdbusplus::message::variant<int, std::string >>;
+          sdbusplus::message::variant<std::string> >;
     auto m = sdbusplus::message::message(msg);
     // message type: sa{sv}as
     std::string ignore;
@@ -109,6 +140,34 @@
     return 0;
 }
 
+void Manager::onPgoodChanged(bool pgood)
+{
+    hostOn = pgood;
+    // TODO: if host is off, check requested time_mode/owner:
+    // and notify the listeners if any.
+}
+
+int Manager::onPgoodChanged(sd_bus_message* msg,
+                            void* userData,
+                            sd_bus_error* retError)
+{
+    using properties = std::map < std::string,
+          sdbusplus::message::variant<int> >;
+    auto m = sdbusplus::message::message(msg);
+    // message type: sa{sv}as
+    std::string ignore;
+    properties props;
+    m.read(ignore, props);
+    for (const auto& item : props)
+    {
+        if (item.first == PGOOD_STR)
+        {
+            static_cast<Manager*>(userData)
+                ->onPgoodChanged(static_cast<bool>(item.second.get<int>()));
+        }
+    }
+    return 0;
+}
 
 void Manager::setCurrentTimeMode(const std::string& mode)
 {
diff --git a/manager.hpp b/manager.hpp
index 65240ac..ef3315f 100644
--- a/manager.hpp
+++ b/manager.hpp
@@ -25,6 +25,10 @@
     public:
         friend class TestManager;
         explicit Manager(sdbusplus::bus::bus& bus);
+        Manager(const Manager&) = delete;
+        Manager& operator=(const Manager&) = delete;
+        Manager(Manager&&) = delete;
+        Manager& operator=(Manager&&) = delete;
 
         /** @brief Add a listener that will be called
           * when property is changed
@@ -38,15 +42,24 @@
         /** @brief The match of settings property change */
         sdbusplus::bus::match::match propertyChangeMatch;
 
+        /** @brief The match of pgood change */
+        sdbusplus::bus::match::match pgoodChangeMatch;
+
         /** @brief The container to hold all the listeners */
         std::set<PropertyChangeListner*> listeners;
 
+        /** @brief The value to indicate if host is on */
+        bool hostOn = false;
+
         /** @brief The current time mode */
         Mode timeMode;
 
         /** @brief The current time owner */
         Owner timeOwner;
 
+        /** @brief Check if host is on and update hostOn variable */
+        void checkHostOn();
+
         /** @brief Get setting from settingsd service
          *
          * @param[in] setting - The string of the setting
@@ -75,6 +88,12 @@
         void onPropertyChanged(const std::string& key,
                                const std::string& value);
 
+        /** @brief Notified on pgood has changed
+         *
+         * @param[in] pgood - The changed pgood value
+         */
+        void onPgoodChanged(bool pgood);
+
         /** @brief The static function called on settings property changed
          *
          * @param[in] msg - Data associated with subscribed signal
@@ -85,6 +104,16 @@
                                      void* userData,
                                      sd_bus_error* retError);
 
+        /** @brief Notified on pgood has changed
+         *
+         * @param[in] msg - Data associated with subscribed signal
+         * @param[in] userData - Pointer to this object instance
+         * @param[out] retError  - Not used but required with signal API
+         */
+        static int onPgoodChanged(sd_bus_message* msg,
+                                  void* userData,
+                                  sd_bus_error* retError);
+
         /** @brief Convert a string to enum Mode
          *
          * Convert the time mode string to enum.