Add support for tracking system power state

Change-Id: Ie0f27f696082ff3ee60c955992f3c2e55f4b5e57
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index 38eddf6..1510753 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -39,12 +39,21 @@
 constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory";
 constexpr auto INVENTORY_INTERFACE = "xyz.openbmc_project.Inventory.Item";
 constexpr auto PRESENT_PROP = "Present";
+constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
+constexpr auto POWER_INTERFACE = "org.openbmc.control.Power";
 
 PowerSupply::PowerSupply(const std::string& name, size_t inst,
-                         const std::string& objpath, const std::string& invpath,
-                         sdbusplus::bus::bus& bus)
-    : Device(name, inst), monitorPath(objpath), inventoryPath(invpath),
-      bus(bus), pmbusIntf(objpath)
+                         const std::string& objpath,
+                         const std::string& invpath,
+                         sdbusplus::bus::bus& bus,
+                         event::Event& e,
+                         std::chrono::seconds& t)
+    : Device(name, inst), monitorPath(objpath), pmbusIntf(objpath),
+      inventoryPath(invpath), bus(bus), event(e), powerOnInterval(t),
+      powerOnTimer(e, [this]()
+                   {
+                       this->powerOn = true;
+                   })
 {
     using namespace sdbusplus::bus;
     auto present_obj_path = INVENTORY_OBJ_PATH + inventoryPath;
@@ -53,13 +62,26 @@
                                                      present_obj_path,
                                                      INVENTORY_INTERFACE),
                                              [this](auto& msg)
-    {
-        this->inventoryChanged(msg);
-    });
-
+                                             {
+                                                 this->inventoryChanged(msg);
+                                             });
+    // Get initial presence state.
     updatePresence();
+
+    // Subscribe to power state changes
+    powerOnMatch = std::make_unique<match_t>(bus,
+                                             match::rules::propertiesChanged(
+                                                     POWER_OBJ_PATH,
+                                                     POWER_INTERFACE),
+                                             [this](auto& msg)
+                                             {
+                                                 this->powerStateChanged(msg);
+                                             });
+    // Get initial power state.
+    updatePowerState();
 }
 
+
 void PowerSupply::analyze()
 {
     using namespace witherspoon::pmbus;
@@ -196,6 +218,74 @@
 
 }
 
+void PowerSupply::powerStateChanged(sdbusplus::message::message& msg)
+{
+    int32_t state = 0;
+    std::string msgSensor;
+    std::map<std::string, sdbusplus::message::variant<int32_t, int32_t>>
+            msgData;
+    msg.read(msgSensor, msgData);
+
+    // Check if it was the Present property that changed.
+    auto valPropMap = msgData.find("state");
+    if (valPropMap != msgData.end())
+    {
+        state = sdbusplus::message::variant_ns::get<int32_t>(valPropMap->second);
+
+        // Power is on when state=1. Set the fault logged variables to false
+        // and start the power on timer when the state changes to 1.
+        if (state)
+        {
+            readFailLogged = false;
+            vinUVFault = false;
+            inputFault = false;
+            powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot);
+        }
+        else
+        {
+            powerOnTimer.stop();
+            powerOn = false;
+        }
+    }
+
+}
+
+void PowerSupply::updatePowerState()
+{
+    // When state = 1, system is powered on
+    int32_t state = 0;
+
+    try
+    {
+        auto service = util::getService(POWER_OBJ_PATH,
+                                        POWER_INTERFACE,
+                                        bus);
+
+        // Use getProperty utility function to get power state.
+        util::getProperty<int32_t>(POWER_INTERFACE,
+                                   "state",
+                                   POWER_OBJ_PATH,
+                                   service,
+                                   bus,
+                                   state);
+
+        if (state)
+        {
+            powerOn = true;
+        }
+        else
+        {
+            powerOn = false;
+        }
+    }
+    catch (std::exception& e)
+    {
+        log<level::INFO>("Failed to get power state. Assuming it is off.");
+        powerOn = false;
+    }
+
+}
+
 void PowerSupply::clearFaults()
 {
     //TODO - Clear faults at pre-poweron. openbmc/openbmc#1736