Add STATUS_WORD to metadata for VIN_UV_FAULT

Change-Id: Iaa6001f7c5d0c558ad3bc01e209dc316236fea93
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/elog-errors.hpp b/elog-errors.hpp
index 7ea5cf3..5a6fad8 100644
--- a/elog-errors.hpp
+++ b/elog-errors.hpp
@@ -544,13 +544,22 @@
 namespace _PowerSupplyUnderVoltageFault
 {
 
+struct RAW_STATUS
+{
+    static constexpr auto str = "RAW_STATUS=%s";
+    static constexpr auto str_short = "RAW_STATUS";
+    using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+    explicit constexpr RAW_STATUS(const char* a) : _entry(entry(str, a)) {};
+    type _entry;
+};
 
 }  // namespace _PowerSupplyUnderVoltageFault
 
 struct PowerSupplyUnderVoltageFault
 {
     static constexpr auto L = level::ERR;
-    using metadata_types = std::tuple<>;
+    using RAW_STATUS = _PowerSupplyUnderVoltageFault::RAW_STATUS;
+    using metadata_types = std::tuple<RAW_STATUS>;
 
 };
 
diff --git a/pmbus.hpp b/pmbus.hpp
index bbe32e4..9254fe7 100644
--- a/pmbus.hpp
+++ b/pmbus.hpp
@@ -11,7 +11,9 @@
 
 namespace fs = std::experimental::filesystem;
 
+// The file name Linux uses to capture the STATUS_WORD from pmbus.
 constexpr auto STATUS_WORD = "status0";
+
 // The file name Linux uses to capture the VIN_UV_FAULT bit from the STATUS_WORD
 constexpr auto VIN_UV_FAULT = "in1_alarm";
 
diff --git a/power-supply/main.cpp b/power-supply/main.cpp
index e36bd24..af6bb9a 100644
--- a/power-supply/main.cpp
+++ b/power-supply/main.cpp
@@ -82,16 +82,12 @@
     //handle both sd_events (for the timers) and dbus signals.
     bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
 
-    // TODO: Use inventory path to subscribe to signal change for power supply presence.
-
     //Attach the event object to the bus object so we can
     //handle both sd_events (for the timers) and dbus signals.
     bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
 
     // TODO: Get power state on startup.
-    // TODO: Get presence state on startup and subscribe to presence changes.
-    // TODO - set to vinUVFault to false on presence change & start of poweron
-    // TODO - set readFailLogged to false on presence change and start of poweron
+
     auto pollInterval = std::chrono::milliseconds(1000);
     DeviceMonitor mainloop(std::move(psuDevice), eventPtr, pollInterval);
     mainloop.run();
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index 8dd4c3e..f70b79d 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -19,6 +19,7 @@
 #include <xyz/openbmc_project/Control/Device/error.hpp>
 #include <xyz/openbmc_project/Power/Fault/error.hpp>
 #include "elog-errors.hpp"
+#include "names_values.hpp"
 #include "power_supply.hpp"
 #include "pmbus.hpp"
 #include "utility.hpp"
@@ -35,6 +36,29 @@
 namespace psu
 {
 
+constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory";
+constexpr auto INVENTORY_INTERFACE = "xyz.openbmc_project.Inventory.Item";
+constexpr auto PRESENT_PROP = "Present";
+
+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)
+{
+    updatePresence();
+
+    using namespace sdbusplus::bus;
+    auto present_obj_path = INVENTORY_OBJ_PATH + inventoryPath;
+    presentMatch = std::make_unique<match_t>(bus,
+                                             match::rules::propertiesChanged(
+                                                     present_obj_path,
+                                                     INVENTORY_INTERFACE),
+                                             [this](auto& msg)
+    {
+        this->inventoryChanged(msg);
+    });
+}
 
 void PowerSupply::analyze()
 {
@@ -42,29 +66,45 @@
 
     try
     {
-        auto curUVFault = pmbusIntf.readBit(VIN_UV_FAULT, Type::Hwmon);
-        //TODO: 3 consecutive reads should be performed.
-        // If 3 consecutive reads are seen, log the fault.
-        // Driver gives cached value, read once a second.
-        // increment for fault on, decrement for fault off, to deglitch.
-        // If count reaches 3, we have fault. If count reaches 0, fault is
-        // cleared.
-
-        //TODO: INPUT FAULT or WARNING bit to check from STATUS_WORD
-        // pmbus-core update to read high byte of STATUS_WORD?
-
-        if ((curUVFault != vinUVFault) || inputFault)
+        if (present)
         {
-            if (curUVFault)
+            auto curUVFault = pmbusIntf.readBit(VIN_UV_FAULT, Type::Hwmon);
+            //TODO: 3 consecutive reads should be performed.
+            // If 3 consecutive reads are seen, log the fault.
+            // Driver gives cached value, read once a second.
+            // increment for fault on, decrement for fault off, to deglitch.
+            // If count reaches 3, we have fault. If count reaches 0, fault is
+            // cleared.
+
+            //TODO: INPUT FAULT or WARNING bit to check from STATUS_WORD
+            // pmbus-core update to read high byte of STATUS_WORD?
+
+            if ((curUVFault != vinUVFault) || inputFault)
             {
-                //FIXME - metadata
-                report<PowerSupplyUnderVoltageFault>();
-                vinUVFault = true;
-            }
-            else
-            {
-                log<level::INFO>("VIN_UV_FAULT cleared");
-                vinUVFault = false;
+
+                if (curUVFault)
+                {
+                    std::uint16_t statusWord = 0;
+                    statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
+
+                    util::NamesValues nv;
+                    nv.add("STATUS_WORD", statusWord);
+
+                    using metadata = xyz::openbmc_project::Power::Fault::
+                            PowerSupplyUnderVoltageFault;
+
+                    report<PowerSupplyUnderVoltageFault>(
+                            metadata::RAW_STATUS(nv.get().c_str()));
+
+                    vinUVFault = true;
+                }
+                else
+                {
+                    log<level::INFO>("VIN_UV_FAULT cleared",
+                                     entry("POWERSUPPLY=%s",
+                                           inventoryPath.c_str()));
+                    vinUVFault = false;
+                }
             }
         }
     }
@@ -82,9 +122,40 @@
     return;
 }
 
+void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
+{
+    std::string msgSensor;
+    std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData;
+    msg.read(msgSensor, msgData);
+
+    // Check if it was the Present property that changed.
+    auto valPropMap = msgData.find(PRESENT_PROP);
+    if (valPropMap != msgData.end())
+    {
+        present = sdbusplus::message::variant_ns::get<bool>(valPropMap->second);
+
+        if (present)
+        {
+            readFailLogged = false;
+            vinUVFault = false;
+        }
+    }
+
+    return;
+}
+
+void PowerSupply::updatePresence()
+{
+    // Use getProperty utility function to get presence status.
+    std::string path = INVENTORY_OBJ_PATH + inventoryPath;
+    std::string service = "xyz.openbmc_project.Inventory.Manager";
+    util::getProperty(INVENTORY_INTERFACE, PRESENT_PROP, path,
+                      service, bus, this->present);
+}
+
 void PowerSupply::clearFaults()
 {
-    //TODO - Clear faults at pre-poweron.
+    //TODO - Clear faults at pre-poweron. openbmc/openbmc#1736
     return;
 }
 
diff --git a/power-supply/power_supply.hpp b/power-supply/power_supply.hpp
index 43489d2..496218f 100644
--- a/power-supply/power_supply.hpp
+++ b/power-supply/power_supply.hpp
@@ -1,4 +1,5 @@
 #pragma once
+#include <sdbusplus/bus/match.hpp>
 #include "device.hpp"
 #include "pmbus.hpp"
 
@@ -9,6 +10,8 @@
 namespace psu
 {
 
+namespace sdbusRule = sdbusplus::bus::match::rules;
+
 /**
  * @class PowerSupply
  * Represents a PMBus power supply device.
@@ -35,11 +38,7 @@
         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)
-        {
-        }
+                    sdbusplus::bus::bus& bus);
 
         /**
          * Power supply specific function to analyze for faults/errors.
@@ -84,6 +83,14 @@
         witherspoon::pmbus::PMBus pmbusIntf;
 
         /**
+         * @brief True if the power supply is present.
+         */
+        bool present = false;
+
+        /** @brief Used to subscribe to dbus pcap propety changes **/
+        std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
+
+        /**
          * @brief Has a PMBus read failure already been logged?
          */
         bool readFailLogged = false;
@@ -103,6 +110,24 @@
          * STATUS_WORD command response.
          */
         bool inputFault = false;
+
+        /** @brief Callback for inventory property changes
+         *
+         * Process change of Present property for power supply.
+         *
+         * @param[in]  msg - Data associated with Present change signal
+         *
+         */
+        void inventoryChanged(sdbusplus::message::message& msg);
+
+        /**
+         * Updates the presence status by querying D-Bus
+         *
+         * The D-Bus inventory properties for this power supply will be read to
+         * determine if the power supply is present or not and update this
+         * objects present member variable to reflect current status.
+         */
+        void updatePresence();
 };
 
 }
diff --git a/xyz/openbmc_project/Power/Fault.metadata.yaml b/xyz/openbmc_project/Power/Fault.metadata.yaml
index 0274523..5f02864 100644
--- a/xyz/openbmc_project/Power/Fault.metadata.yaml
+++ b/xyz/openbmc_project/Power/Fault.metadata.yaml
@@ -1,5 +1,8 @@
 - name: PowerSupplyUnderVoltageFault
   level: ERR
+  meta:
+    - str: "RAW_STATUS=%s"
+      type: string
 - name: Shutdown
   level: ERR