dcmi: asset-tag: Add API to read asset tag from dbus

Change-Id: I00958d4bb54896ea7d13aaffd7e0ebf3c20ef3de
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/dcmihandler.cpp b/dcmihandler.cpp
index 19187ba..c7497f0 100644
--- a/dcmihandler.cpp
+++ b/dcmihandler.cpp
@@ -1,8 +1,15 @@
-#include "dcmihandler.h"
+#include "dcmihandler.hpp"
 #include "host-ipmid/ipmid-api.h"
+#include <phosphor-logging/elog-errors.hpp>
 #include <stdio.h>
 #include <string.h>
 #include <stdint.h>
+#include "utils.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+using namespace phosphor::logging;
+using InternalFailure =
+        sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
 
 void register_netfn_dcmi_functions() __attribute__((constructor));
 
@@ -30,6 +37,75 @@
     return rc;
 }
 
+namespace dcmi
+{
+
+void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
+{
+    static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
+    static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
+    static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
+    static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
+
+    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+    auto depth = 0;
+
+    auto mapperCall = bus.new_method_call(mapperBusName,
+                                          mapperObjPath,
+                                          mapperIface,
+                                          "GetSubTree");
+
+    mapperCall.append(inventoryRoot);
+    mapperCall.append(depth);
+    mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
+
+    auto mapperReply = bus.call(mapperCall);
+    if (mapperReply.is_method_error())
+    {
+        log<level::ERR>("Error in mapper call");
+        elog<InternalFailure>();
+    }
+
+    mapperReply.read(objectTree);
+
+    if (objectTree.empty())
+    {
+        log<level::ERR>("AssetTag property is not populated");
+        elog<InternalFailure>();
+    }
+}
+
+std::string readAssetTag()
+{
+    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+    dcmi::assettag::ObjectTree objectTree;
+
+    // Read the object tree with the inventory root to figure out the object
+    // that has implemented the Asset tag interface.
+    readAssetTagObjectTree(objectTree);
+
+    auto method = bus.new_method_call(
+            (objectTree.begin()->second.begin()->first).c_str(),
+            (objectTree.begin()->first).c_str(),
+            dcmi::propIntf,
+            "Get");
+    method.append(dcmi::assetTagIntf);
+    method.append(dcmi::assetTagProp);
+
+    auto reply = bus.call(method);
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Error in reading asset tag");
+        elog<InternalFailure>();
+    }
+
+    sdbusplus::message::variant<std::string> assetTag;
+    reply.read(assetTag);
+
+    return assetTag.get<std::string>();
+}
+
+} // namespace dcmi
 
 void register_netfn_dcmi_functions()
 {
diff --git a/dcmihandler.h b/dcmihandler.h
deleted file mode 100644
index 5fc0c10..0000000
--- a/dcmihandler.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __HOST_IPMI_DCMI_HANDLER_H__
-#define __HOST_IPMI_DCMI_HANDLER_H__
-
-// IPMI commands for net functions.
-enum ipmi_netfn_sen_cmds
-{
-    // Get capability bits
-    IPMI_CMD_DCMI_GET_POWER = 0x03,
-    
-};
-
-#endif
diff --git a/dcmihandler.hpp b/dcmihandler.hpp
new file mode 100644
index 0000000..dfe1d4e
--- /dev/null
+++ b/dcmihandler.hpp
@@ -0,0 +1,51 @@
+#ifndef __HOST_IPMI_DCMI_HANDLER_H__
+#define __HOST_IPMI_DCMI_HANDLER_H__
+
+#include <map>
+#include <string>
+#include <vector>
+
+// IPMI commands for net functions.
+enum ipmi_netfn_sen_cmds
+{
+    // Get capability bits
+    IPMI_CMD_DCMI_GET_POWER = 0x03,
+};
+
+namespace dcmi
+{
+
+static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
+static constexpr auto assetTagIntf =
+        "xyz.openbmc_project.Inventory.Decorator.AssetTag";
+static constexpr auto assetTagProp = "AssetTag";
+
+namespace assettag
+{
+
+    using ObjectPath = std::string;
+    using Service = std::string;
+    using Interfaces = std::vector<std::string>;
+    using ObjectTree = std::map<ObjectPath, std::map<Service, Interfaces>>;
+
+} //namespace assettag
+
+/** @brief Read the object tree to fetch the object path that implemented the
+ *         Asset tag interface.
+ *
+ *  @param[in,out] objectTree - object tree
+ *
+ *  @return On success return the object tree with the object path that
+ *          implemented the AssetTag interface.
+ */
+void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree);
+
+/** @brief Read the asset tag of the server
+ *
+ *  @return On success return the asset tag.
+ */
+std::string readAssetTag();
+
+} // namespace dcmi
+
+#endif