Add STATUS_WORD to metadata for VIN_UV_FAULT

Change-Id: Iaa6001f7c5d0c558ad3bc01e209dc316236fea93
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
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;
 }