Add inventory update support

Set a fan's Functional property to false when
it has been out of spec for too long.  When it
is back in spec, set it back to functional.

Change-Id: I264129479c58fd296df7c3a1d3d42f5d7aa7b60b
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/monitor/fan.cpp b/monitor/fan.cpp
index d1101b9..639d88e 100644
--- a/monitor/fan.cpp
+++ b/monitor/fan.cpp
@@ -17,6 +17,7 @@
 #include <phosphor-logging/log.hpp>
 #include "fan.hpp"
 #include "types.hpp"
+#include "utility.hpp"
 
 namespace phosphor
 {
@@ -28,6 +29,14 @@
 using namespace phosphor::logging;
 using TimerType = phosphor::fan::util::Timer::TimerType;
 
+constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
+constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
+
+constexpr auto FUNCTIONAL_PROPERTY = "Functional";
+constexpr auto OPERATIONAL_STATUS_INTF  =
+    "xyz.openbmc_project.State.Decorator.OperationalStatus";
+
+
 Fan::Fan(sdbusplus::bus::bus& bus,
          std::shared_ptr<sd_event>&  events,
          const FanDefinition& def) :
@@ -49,6 +58,9 @@
                                          events));
     }
 
+    //Start from a known state of functional
+    updateInventory(true);
+
     //The TachSensors will now have already read the input
     //and target values, so check them.
     tachChanged();
@@ -101,7 +113,7 @@
             log<level::INFO>("Setting a fan back to functional",
                              entry("FAN=%s", _name.c_str()));
 
-            //TODO: actually update inventory
+            updateInventory(true);
         }
     }
 }
@@ -171,9 +183,64 @@
     //If the fan is currently functional, but too many
     //contained sensors are now nonfunctional, update
     //the whole fan nonfunctional.
-    //TODO
+
+    if (_functional && tooManySensorsNonfunctional())
+    {
+        log<level::ERR>("Setting a fan to nonfunctional",
+                        entry("FAN=%s", _name.c_str()));
+
+        updateInventory(false);
+    }
 }
 
+
+void Fan::updateInventory(bool functional)
+{
+    ObjectMap objectMap = getObjectMap(functional);
+    std::string service;
+
+    try
+    {
+        service = phosphor::fan::util::getInvService(_bus);
+    }
+    catch (const std::runtime_error& err)
+    {
+        log<level::ERR>(err.what());
+        return;
+    }
+
+    auto msg = _bus.new_method_call(service.c_str(),
+                                   INVENTORY_PATH,
+                                   INVENTORY_INTF,
+                                   "Notify");
+
+    msg.append(std::move(objectMap));
+    auto response = _bus.call(msg);
+    if (response.is_method_error())
+    {
+        log<level::ERR>("Error in Notify call to update inventory");
+        return;
+    }
+
+    //This will always track the current state of the inventory.
+    _functional = functional;
+}
+
+
+Fan::ObjectMap Fan::getObjectMap(bool functional)
+{
+    ObjectMap objectMap;
+    InterfaceMap interfaceMap;
+    PropertyMap propertyMap;
+
+    propertyMap.emplace(FUNCTIONAL_PROPERTY, functional);
+    interfaceMap.emplace(OPERATIONAL_STATUS_INTF, std::move(propertyMap));
+    objectMap.emplace(_name, std::move(interfaceMap));
+
+    return objectMap;
+}
+
+
 }
 }
 }