Update inventory item interface

Update the inventory item interface, setting
Present and PrettyName.

Change-Id: I6a0a8bd66a8427253706b2b1ee14dca919d0a809
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/presence/gpio_presence.cpp b/presence/gpio_presence.cpp
index 710e4ae..ba897d0 100644
--- a/presence/gpio_presence.cpp
+++ b/presence/gpio_presence.cpp
@@ -16,6 +16,50 @@
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 
+constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
+constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
+
+constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
+constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
+
+std::string getService(const std::string& path,
+                       const std::string& interface,
+                       sdbusplus::bus::bus& bus)
+{
+    auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
+                                          MAPPER_PATH,
+                                          MAPPER_INTERFACE,
+                                          "GetObject");
+
+    mapperCall.append(path);
+    mapperCall.append(std::vector<std::string>({interface}));
+
+    auto mapperResponseMsg = bus.call(mapperCall);
+    if (mapperResponseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mapper call to get service name",
+                        entry("PATH=%s", path.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+
+    std::map<std::string, std::vector<std::string>> mapperResponse;
+    mapperResponseMsg.read(mapperResponse);
+
+    if (mapperResponse.empty())
+    {
+        log<level::ERR>(
+            "Error in mapper response for getting service name",
+            entry("PATH=%s", path.c_str()),
+            entry("INTERFACE=%s", interface.c_str()));
+        elog<InternalFailure>();
+    }
+
+    return mapperResponse.begin()->first;
+}
+
 // Populate the file descriptor for passed in device
 int Presence::openDevice()
 {
@@ -56,6 +100,7 @@
 
 void Presence::determinePresence()
 {
+    auto present = false;
     auto value = static_cast<int>(0);
     auto fetch_rc = libevdev_fetch_event_value(devicePtr.get(), EV_KEY,
                     key, &value);
@@ -66,8 +111,52 @@
         elog<InternalFailure>();
         return;
     }
+    if (value > 0)
+    {
+        present = true;
+    }
+
+    updateInventory(present);
 }
 
+
+Presence::ObjectMap Presence::getObjectMap(bool present)
+{
+    ObjectMap invObj;
+    InterfaceMap invIntf;
+    PropertyMap invProp;
+
+    invProp.emplace("Present", present);
+    invProp.emplace("PrettyName", name);
+    invIntf.emplace("xyz.openbmc_project.Inventory.Item",
+                    std::move(invProp));
+    invObj.emplace(std::move(inventory), std::move(invIntf));
+
+    return invObj;
+}
+
+void Presence::updateInventory(bool present)
+{
+    ObjectMap invObj = getObjectMap(present);
+
+    auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
+
+    // Update inventory
+    auto invMsg = bus.new_method_call(invService.c_str(),
+                                      INVENTORY_PATH,
+                                      INVENTORY_INTF,
+                                      "Notify");
+    invMsg.append(std::move(invObj));
+    auto invMgrResponseMsg = bus.call(invMsg);
+    if (invMgrResponseMsg.is_method_error())
+    {
+        log<level::ERR>(
+            "Error in inventory manager call to update inventory");
+        elog<InternalFailure>();
+    }
+}
+
+
 } // namespace presence
 } // namespace gpio
 } // namespace phosphor
diff --git a/presence/gpio_presence.hpp b/presence/gpio_presence.hpp
index 3faa7e1..47d2dc7 100644
--- a/presence/gpio_presence.hpp
+++ b/presence/gpio_presence.hpp
@@ -27,6 +27,17 @@
 class Presence
 {
 
+        using Property = std::string;
+        using Value = sdbusplus::message::variant<bool, std::string>;
+        // Association between property and its value
+        using PropertyMap = std::map<Property, Value>;
+        using Interface = std::string;
+        // Association between interface and the D-Bus property
+        using InterfaceMap = std::map<Interface, PropertyMap>;
+        using Object = sdbusplus::message::object_path;
+        // Association between object and the interface
+        using ObjectMap = std::map<Object, InterfaceMap>;
+
     public:
         Presence() = delete;
         ~Presence() = default;
@@ -37,6 +48,7 @@
 
         /** @brief Constructs Presence object.
          *
+         *  @param[in] bus       - D-Bus bus Object
          *  @param[in] inventory - Object path under inventory
                                    to display this inventory item
          *  @param[in] path      - Device path to read for GPIO pin state
@@ -44,10 +56,12 @@
          *  @param[in] key       - GPIO key to monitor
          *  @param[in] name      - Pretty name of the inventory item
          */
-        Presence(const std::string& inventory,
+        Presence(sdbusplus::bus::bus& bus,
+                 const std::string& inventory,
                  const std::string& path,
                  const unsigned int key,
                  const std::string& name) :
+            bus(bus),
             inventory(inventory),
             path(path),
             key(key),
@@ -60,6 +74,25 @@
 
     private:
         /**
+         * @brief Update the present property for the inventory item.
+         *
+         * @param[in] present - What the present property should be set to.
+         */
+        void updateInventory(bool present);
+
+        /**
+         * @brief Construct the inventory object map for the inventory item.
+         *
+         * @param[in] present - What the present property should be set to.
+         *
+         * @return The inventory object map to update inventory
+         */
+        ObjectMap getObjectMap(bool present);
+
+        /** @brief Connection for sdbusplus bus */
+        sdbusplus::bus::bus& bus;
+
+        /**
          * @brief Read the GPIO device to determine initial presence and set
          *        present property at D-Bus path.
          **/
@@ -91,6 +124,20 @@
         void initEvDev();
 };
 
+/**
+ * @brief Get the service name from the mapper for the
+ *        interface and path passed in.
+ *
+ * @param[in] path      - The D-Bus path name
+ * @param[in] interface - The D-Bus interface name
+ * @param[in] bus       - The D-Bus bus object
+ *
+ * @return The service name
+ */
+std::string getService(const std::string& path,
+                       const std::string& interface,
+                       sdbusplus::bus::bus& bus);
+
 } // namespace presence
 } // namespace gpio
 } // namespace phosphor
diff --git a/presence/main.cpp b/presence/main.cpp
index 8935568..f6cb665 100644
--- a/presence/main.cpp
+++ b/presence/main.cpp
@@ -37,7 +37,10 @@
         std::cerr << "Device path argument required\n";
         options.usage(argv);
     }
-    Presence presence(inventory, path, std::stoul(key), options["name"]);
+
+    auto bus = sdbusplus::bus::new_default();
+    auto name = options["name"];
+    Presence presence(bus, inventory, path, std::stoul(key), name);
 
     return 0;
 }