DBus calls to update VPD cache data for Interfaces

This commit implements required bus call to update vpd cache
once the data has been updated on the hardware.
It updates data for Common interface,Extra interface and COM
interface.

To test on simics use following procedure
- Hexdump the vpd file of EEPROM you want
to update in a .txt file.
- To update data of keyword for any record
make "busctl call" to WriteKeyword.
-After successful execution, agaim hexdump
VPD file of same EEPROM in another .txt
file.
-Difference can be observed in both the
file w.r.t. updated data and ECC.

once complete call has been made, updated
data in cache can be seen using following command
on simics.
- busctl intrsopect <service> <object_path>
- busctl introspect <service> <object_path>
<interface_name>

Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: I7997a027b631de25e254be9811c1926902fda8ec
diff --git a/const.hpp b/const.hpp
index e986425..13d61af 100644
--- a/const.hpp
+++ b/const.hpp
@@ -44,8 +44,9 @@
 constexpr uint8_t KW_VAL_PAIR_START_TAG = 0x84;
 constexpr uint8_t RECORD_END_TAG = 0x78;
 
-const std::string service = "xyz.openbmc_project.Inventory.Manager";
-const std::string VPD_OBJ_PATH_PREFIX = "/xyz/openbmc_project/inventory";
+static constexpr auto service = "xyz.openbmc_project.Inventory.Manager";
+static constexpr auto VPD_OBJ_PATH_PREFIX = "/xyz/openbmc_project/inventory";
+static constexpr auto COM_INTERFACE_PREFIX = "com.ibm.ipzvpd";
 
 namespace lengths
 {
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index ddbf7e9..1dc0f97 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -20,48 +20,6 @@
 using namespace vpd::keyword::parser;
 using namespace vpdFormat;
 
-/** @brief Encodes a keyword for D-Bus.
- */
-static string encodeKeyword(const string& kw, const string& encoding)
-{
-    if (encoding == "MAC")
-    {
-        string res{};
-        size_t first = kw[0];
-        res += toHex(first >> 4);
-        res += toHex(first & 0x0f);
-        for (size_t i = 1; i < kw.size(); ++i)
-        {
-            res += ":";
-            res += toHex(kw[i] >> 4);
-            res += toHex(kw[i] & 0x0f);
-        }
-        return res;
-    }
-    else if (encoding == "DATE")
-    {
-        // Date, represent as
-        // <year>-<month>-<day> <hour>:<min>
-        string res{};
-        static constexpr uint8_t skipPrefix = 3;
-
-        auto strItr = kw.begin();
-        advance(strItr, skipPrefix);
-        for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
-
-        res.insert(BD_YEAR_END, 1, '-');
-        res.insert(BD_MONTH_END, 1, '-');
-        res.insert(BD_DAY_END, 1, ' ');
-        res.insert(BD_HOUR_END, 1, ':');
-
-        return res;
-    }
-    else // default to string encoding
-    {
-        return string(kw.begin(), kw.end());
-    }
-}
-
 /** @brief Reads a property from the inventory manager given object path,
  * intreface and property.
  */
diff --git a/utils.cpp b/utils.cpp
index e0bf6f4..6f2bfe4 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -1,6 +1,7 @@
 #include "utils.hpp"
 
-#include <iostream>
+#include "defines.hpp"
+
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/server.hpp>
 
@@ -74,5 +75,46 @@
     return lowByte;
 }
 
+/** @brief Encodes a keyword for D-Bus.
+ */
+string encodeKeyword(const string& kw, const string& encoding)
+{
+    if (encoding == "MAC")
+    {
+        string res{};
+        size_t first = kw[0];
+        res += toHex(first >> 4);
+        res += toHex(first & 0x0f);
+        for (size_t i = 1; i < kw.size(); ++i)
+        {
+            res += ":";
+            res += toHex(kw[i] >> 4);
+            res += toHex(kw[i] & 0x0f);
+        }
+        return res;
+    }
+    else if (encoding == "DATE")
+    {
+        // Date, represent as
+        // <year>-<month>-<day> <hour>:<min>
+        string res{};
+        static constexpr uint8_t skipPrefix = 3;
+
+        auto strItr = kw.begin();
+        advance(strItr, skipPrefix);
+        for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
+
+        res.insert(BD_YEAR_END, 1, '-');
+        res.insert(BD_MONTH_END, 1, '-');
+        res.insert(BD_DAY_END, 1, ' ');
+        res.insert(BD_HOUR_END, 1, ':');
+
+        return res;
+    }
+    else // default to string encoding
+    {
+        return string(kw.begin(), kw.end());
+    }
+}
 } // namespace vpd
 } // namespace openpower
diff --git a/utils.hpp b/utils.hpp
index 59b33ea..fd12698 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -3,6 +3,9 @@
 #include "const.hpp"
 #include "types.hpp"
 
+#include <iostream>
+
+using namespace std;
 namespace openpower
 {
 namespace vpd
@@ -40,5 +43,10 @@
 openpower::vpd::constants::LE2ByteData
     readUInt16LE(Binary::const_iterator iterator);
 
+/** @brief Encodes a keyword for D-Bus.
+ *  @param[in] kw - kwd data in string format
+ *  @param[in] encoding - required for kwd data
+ */
+string encodeKeyword(const string& kw, const string& encoding);
 } // namespace vpd
 } // namespace openpower
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index 091eac4..c9e9847 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -3,10 +3,6 @@
 #include "parser.hpp"
 #include "utils.hpp"
 
-#include <fstream>
-#include <iostream>
-#include <iterator>
-
 #include "vpdecc/vpdecc.h"
 
 namespace openpower
@@ -250,18 +246,48 @@
     checkPTForRecord(itrToRecord, ptLen);
 }
 
+template <typename T>
+void EditorImpl::makeDbusCall(const std::string& object,
+                              const std::string& interface,
+                              const std::string& property,
+                              const std::variant<T>& data)
+{
+    auto bus = sdbusplus::bus::new_default();
+    auto properties = bus.new_method_call(
+        service, object.c_str(), "org.freedesktop.DBus.Properties", "Set");
+    properties.append(interface);
+    properties.append(property);
+    properties.append(data);
+
+    auto result = bus.call(properties);
+
+    if (result.is_method_error())
+    {
+        throw std::runtime_error("bus call failed");
+    }
+}
+
 void EditorImpl::processAndUpdateCI(const std::string& objectPath)
 {
     for (auto& commonInterface : jsonFile["commonInterfaces"].items())
     {
         for (auto& ciPropertyList : commonInterface.value().items())
         {
-            if ((ciPropertyList.value().value("recordName", "") ==
-                 thisRecord.recName) &&
-                (ciPropertyList.value().value("keywordName", "") ==
-                 thisRecord.recKWd))
+            if (ciPropertyList.value().type() ==
+                nlohmann::json::value_t::object)
             {
-                // implement busctl call here
+                if ((ciPropertyList.value().value("recordName", "") ==
+                     thisRecord.recName) &&
+                    (ciPropertyList.value().value("keywordName", "") ==
+                     thisRecord.recKWd))
+                {
+                    std::string kwdData(thisRecord.kwdUpdatedData.begin(),
+                                        thisRecord.kwdUpdatedData.end());
+
+                    makeDbusCall<std::string>(
+                        (VPD_OBJ_PATH_PREFIX + objectPath),
+                        commonInterface.key(), ciPropertyList.key(), kwdData);
+                }
             }
         }
     }
@@ -276,12 +302,22 @@
         {
             for (const auto& eiPropertyList : extraInterface.value().items())
             {
-                if ((eiPropertyList.value().value("recordName", "") ==
-                     thisRecord.recName) &&
-                    ((eiPropertyList.value().value("keywordName", "") ==
-                      thisRecord.recKWd)))
+                if (eiPropertyList.value().type() ==
+                    nlohmann::json::value_t::object)
                 {
-                    // implement busctl call here
+                    if ((eiPropertyList.value().value("recordName", "") ==
+                         thisRecord.recName) &&
+                        ((eiPropertyList.value().value("keywordName", "") ==
+                          thisRecord.recKWd)))
+                    {
+                        std::string kwdData(thisRecord.kwdUpdatedData.begin(),
+                                            thisRecord.kwdUpdatedData.end());
+                        makeDbusCall<std::string>(
+                            (VPD_OBJ_PATH_PREFIX + objPath),
+                            extraInterface.key(), eiPropertyList.key(),
+                            encodeKeyword(kwdData, eiPropertyList.value().value(
+                                                       "encoding", "")));
+                    }
                 }
             }
         }
@@ -296,13 +332,24 @@
     // iterate through all the inventories for this file path
     for (const auto& singleInventory : groupEEPROM)
     {
-        // process and update CI
-        const std::string& LocationCode =
-            singleInventory["extraInterfaces"][LOCATION_CODE_INF]
-                           ["LocationCode"]
-                               .get_ref<const nlohmann::json::string_t&>();
-        if (LocationCode.substr(1, 3) != "mts")
+        // by default inherit property is true
+        bool isInherit = true;
+
+        if (singleInventory.find("inherit") != singleInventory.end())
         {
+            isInherit = singleInventory["inherit"].get<bool>();
+        }
+
+        if (isInherit)
+        {
+            // update com interface
+            makeDbusCall<Binary>(
+                (VPD_OBJ_PATH_PREFIX +
+                 singleInventory["inventoryPath"].get<std::string>()),
+                (COM_INTERFACE_PREFIX + (std::string) "." + thisRecord.recName),
+                thisRecord.recKWd, thisRecord.kwdUpdatedData);
+
+            // process Common interface
             processAndUpdateCI(singleInventory["inventoryPath"]
                                    .get_ref<const nlohmann::json::string_t&>());
         }
diff --git a/vpd-manager/editor_impl.hpp b/vpd-manager/editor_impl.hpp
index ff94692..8e113b1 100644
--- a/vpd-manager/editor_impl.hpp
+++ b/vpd-manager/editor_impl.hpp
@@ -122,6 +122,18 @@
     void processAndUpdateEI(const nlohmann::json& Inventory,
                             const inventory::Path& objPath);
 
+    /** @brief method to make busctl call
+     *
+     *  @param[in] object - bus object path
+     *  @param[in] interface - bus interface
+     *  @param[in] property - property to update on BUS
+     *  @param[in] data - data to be updayed on Bus
+     *
+     */
+    template <typename T>
+    void makeDbusCall(const std::string& object, const std::string& interface,
+                      const std::string& property, const std::variant<T>& data);
+
     // path to the VPD file to edit
     const inventory::Path& vpdFilePath;
 
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index dfcdc39..37a8055 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -2,7 +2,7 @@
 
 #include "manager.hpp"
 
-#include "const.hpp"
+#include "editor_impl.hpp"
 #include "parser.hpp"
 
 using namespace openpower::vpd::constants;