VPD Tool: Update Hardware

Vpd tool has --Hardware/-H flag which should be given along
with writeKeyword flags, if the user wants to write directly to "Hardware".

In general the user should give only the object path in
--path/-P value.

Only if --Hardware/-H flag is given, the user has an
option to give either eeprom path or the object path in
--path/-P value.

Test:
Tested on simics.

./vpd-tool --writeKeyword -H --path < hardware path/object path > -R < record name > -K < keyword > -V < value in hex/ascii >

CASE 1: <updating eeprom path> < update directly on hardware using -H.>
./vpd-tool -u -H -P /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem -R VINI -K PN -V 0x717273
updation successful on both dbus and hardware.

CASE 2:
./vpd-tool -u -H -P /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem -R DINF -K FL -V 0x717273
updation successful on hardware. <this wont get updated in dbus as the given record-keyword pair is not required to update in dbus(only those record keywords
present in dbus_properties.json are required to be updated in dbus).

CASE 3: <failure case - invalid eeprom path>
root@rainier:/tmp# ./vpd-tool -u -H -P /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a490.i2c-bus/i2c-8/8-0051/8-00510/nvmem -R VINI -K PN -V 0x717273
Invalid object path : /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a490.i2c-bus/i2c-8/8-0051/8-00510/nvmem. Unable to find the corresponding EEPROM path for the given object path : /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e7$

Signed-off-by: PriyangaRamasamy <priyanga24@in.ibm.com>
Change-Id: I6b893e699fe343c90c3a3fd2b07fd8b9a4711687
diff --git a/meson.build b/meson.build
index d5080b3..1a44195 100644
--- a/meson.build
+++ b/meson.build
@@ -47,22 +47,23 @@
                        'INVENTORY_JSON_SYM_LINK': '"'+get_option('INVENTORY_JSON_SYM_LINK')+'"',
                        'INVENTORY_JSON_2U': '"'+get_option('INVENTORY_JSON_2U')+'"',
                        'INVENTORY_JSON_4U': '"'+get_option('INVENTORY_JSON_4U')+'"',
-                       'INVENTORY_JSON_EVEREST': '"'+get_option('INVENTORY_JSON_EVEREST')+'"'
+                       'INVENTORY_JSON_EVEREST': '"'+get_option('INVENTORY_JSON_EVEREST')+'"',
+                       'DBUS_PROP_JSON': '"'+get_option('DBUS_PROP_JSON')+'"'
                        }
   )
 
+common_SOURCES =[
+'vpd-parser/parser_factory.cpp',
+                 'vpd-parser/memory_vpd_parser.cpp',
+                 'vpd-parser/keyword_vpd_parser.cpp',
+                 'vpd-parser/ipz_parser.cpp', 'impl.cpp', 'utils.cpp',
+                 'vpdecc/vpdecc.c', 'vpdecc/vpdecc_support.c'
+]
+
 if get_option('ibm-parser').enabled()
         libgpiodcxx = dependency('libgpiodcxx')
-        ibm_read_vpd_SOURCES = ['ibm_vpd_app.cpp',
-                                'vpd-parser/ipz_parser.cpp',
-                                'impl.cpp',
-                                'utils.cpp',
-                                'vpd-parser/keyword_vpd_parser.cpp',
-                                'vpdecc/vpdecc.c',
-                                'vpdecc/vpdecc_support.c',
-                                'vpd-parser/memory_vpd_parser.cpp',
-                                'vpd-parser/parser_factory.cpp'
-                               ]
+        ibm_read_vpd_SOURCES = ['ibm_vpd_app.cpp'
+                               ]+common_SOURCES
 
         ibm_vpd_exe = executable(
                                 'ibm-read-vpd',
@@ -78,8 +79,11 @@
                             )
 
         vpd_tool_SOURCES = ['vpd_tool.cpp',
-                            'vpd_tool_impl.cpp'
-                           ]
+                            'vpd_tool_impl.cpp',
+                            'vpd-manager/editor_impl.cpp',
+                           ]+common_SOURCES
+
+        vpd_tool_INCLUDE = include_directories('vpd-parser/', 'vpd-manager')
 
         vpd_tool_exe = executable(
                                  'vpd-tool',
@@ -87,7 +91,8 @@
                                  dependencies: [
                                    sdbusplus
                                    ],
-                                 install: true
+                                 install: true,
+                                 include_directories : vpd_tool_INCLUDE
                                  )
 if get_option('vpd-manager').enabled()
     subdir('vpd-manager')
diff --git a/meson_options.txt b/meson_options.txt
index 46adce4..f5c839c 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -20,3 +20,4 @@
 option('INVENTORY_JSON_2U',type: 'string', value: '/usr/share/vpd/50001001.json',  description: 'Inventory JSON for 2U system.')
 option('INVENTORY_JSON_4U',type: 'string', value: '/usr/share/vpd/50001000.json',  description: 'Inventory JSON for 4U system.')
 option('INVENTORY_JSON_EVEREST',type: 'string', value: '/usr/share/vpd/50003000.json',  description: 'Inventory JSON for Everest system.')
+option('DBUS_PROP_JSON',type: 'string', value: '/usr/share/vpd/dbus_properties.json',  description: 'Json which contains properties specific to dbus.')
diff --git a/test/vpd-manager-test/editor_test.cpp b/test/vpd-manager-test/editor_test.cpp
index 2f7114a..1549df8 100644
--- a/test/vpd-manager-test/editor_test.cpp
+++ b/test/vpd-manager-test/editor_test.cpp
@@ -87,7 +87,7 @@
     {
         // Invalid kwd name
         EditorImpl edit("VINI", "SN", std::move(emptyVpdFile));
-        edit.updateKeyword(dataToUodate);
+        edit.updateKeyword(dataToUodate, true);
     }
     catch (const std::exception& e)
     {
@@ -105,7 +105,7 @@
     {
         // the path is dummy
         EditorImpl edit("VINI", "SN", std::move(vpd));
-        edit.updateKeyword(dataToUodate);
+        edit.updateKeyword(dataToUodate, true);
     }
     catch (const std::exception& e)
     {
@@ -124,7 +124,7 @@
     {
         // Invalid record name "VIN", path is dummy
         EditorImpl edit("VIN", "SN", std::move(vpd));
-        edit.updateKeyword(dataToUodate);
+        edit.updateKeyword(dataToUodate, true);
     }
     catch (const std::exception& e)
     {
@@ -143,7 +143,7 @@
     {
         // All valid data
         EditorImpl edit("VINI", "Sn", std::move(vpd));
-        edit.updateKeyword(dataToUodate);
+        edit.updateKeyword(dataToUodate, true);
     }
     catch (std::runtime_error& e)
     {
@@ -162,7 +162,7 @@
     {
         // All valid data
         EditorImpl edit("VINI", "SN", std::move(vpd));
-        edit.updateKeyword(dataToUodate);
+        edit.updateKeyword(dataToUodate, true);
     }
     catch (std::runtime_error& e)
     {
@@ -176,4 +176,4 @@
     ::testing::InitGoogleTest(&argc, argv);
 
     return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/utils.cpp b/utils.cpp
index b9d07e4..69fbe6e 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -3,12 +3,19 @@
 #include "utils.hpp"
 
 #include "defines.hpp"
+#include "vpd_exceptions.hpp"
 
+#include <fstream>
+#include <iomanip>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/server.hpp>
+#include <sstream>
+#include <vector>
 #include <xyz/openbmc_project/Common/error.hpp>
 
+using json = nlohmann::json;
+
 namespace openpower
 {
 namespace vpd
@@ -17,7 +24,8 @@
 using namespace inventory;
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
-
+using namespace record;
+using namespace openpower::vpd::exceptions;
 namespace inventory
 {
 
@@ -230,5 +238,113 @@
             "Error in invoking D-Bus logging create interface to register PEL");
     }
 }
+
+inventory::VPDfilepath getVpdFilePath(const string& jsonFile,
+                                      const std::string& ObjPath)
+{
+    ifstream inventoryJson(jsonFile);
+    const auto& jsonObject = json::parse(inventoryJson);
+    inventory::VPDfilepath filePath{};
+
+    if (jsonObject.find("frus") == jsonObject.end())
+    {
+        throw(VpdJsonException(
+            "Invalid JSON structure - frus{} object not found in ", jsonFile));
+    }
+
+    const nlohmann::json& groupFRUS =
+        jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
+    for (const auto& itemFRUS : groupFRUS.items())
+    {
+        const std::vector<nlohmann::json>& groupEEPROM =
+            itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
+        for (const auto& itemEEPROM : groupEEPROM)
+        {
+            if (itemEEPROM["inventoryPath"]
+                    .get_ref<const nlohmann::json::string_t&>() == ObjPath)
+            {
+                filePath = itemFRUS.key();
+                return filePath;
+            }
+        }
+    }
+
+    return filePath;
+}
+
+bool isPathInJson(const std::string& eepromPath)
+{
+    bool present = false;
+    ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
+
+    try
+    {
+        auto js = json::parse(inventoryJson);
+        if (js.find("frus") == js.end())
+        {
+            throw(VpdJsonException(
+                "Invalid JSON structure - frus{} object not found in ",
+                INVENTORY_JSON_SYM_LINK));
+        }
+        json fruJson = js["frus"];
+
+        if (fruJson.find(eepromPath) != fruJson.end())
+        {
+            present = true;
+        }
+    }
+    catch (json::parse_error& ex)
+    {
+        throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
+    }
+    return present;
+}
+
+bool isRecKwInDbusJson(const std::string& recordName,
+                       const std::string& keyword)
+{
+    ifstream propertyJson(DBUS_PROP_JSON);
+    json dbusProperty;
+    bool present = false;
+
+    if (propertyJson.is_open())
+    {
+        try
+        {
+            auto dbusPropertyJson = json::parse(propertyJson);
+            if (dbusPropertyJson.find("dbusProperties") ==
+                dbusPropertyJson.end())
+            {
+                throw(VpdJsonException("dbusProperties{} object not found in "
+                                       "DbusProperties json : ",
+                                       DBUS_PROP_JSON));
+            }
+
+            dbusProperty = dbusPropertyJson["dbusProperties"];
+            if (dbusProperty.contains(recordName))
+            {
+                const vector<string>& kwdsToPublish = dbusProperty[recordName];
+                if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
+                    kwdsToPublish.end()) // present
+                {
+                    present = true;
+                }
+            }
+        }
+        catch (json::parse_error& ex)
+        {
+            throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
+        }
+    }
+    else
+    {
+        // If dbus properties json is not available, we assume the given
+        // record-keyword is part of dbus-properties json. So setting the bool
+        // variable to true.
+        present = true;
+    }
+    return present;
+}
+
 } // namespace vpd
 } // namespace openpower
diff --git a/utils.hpp b/utils.hpp
index 2c748ee..94f4992 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -4,6 +4,7 @@
 #include "types.hpp"
 
 #include <iostream>
+#include <nlohmann/json.hpp>
 
 using namespace std;
 
@@ -108,5 +109,35 @@
 void createPEL(const std::map<std::string, std::string>& additionalData,
                const std::string& errIntf);
 
+/**
+ * @brief getVpdFilePath
+ * Get vpd file path corresponding to the given object path.
+ * @param[in] - json file path
+ * @param[in] - Object path
+ * @return - Vpd file path
+ */
+inventory::VPDfilepath getVpdFilePath(const string& jsonFile,
+                                      const std::string& ObjPath);
+
+/**
+ * @brief isPathInJson
+ * API which checks for the presence of the given eeprom path in the given json.
+ * @param[in] - eepromPath
+ * @return - true if the eeprom is present in the json; false otherwise
+ */
+bool isPathInJson(const std::string& eepromPath);
+
+/**
+ * @brief isRecKwInDbusJson
+ * API which checks whether the given keyword under the given record is to be
+ * published on dbus or not. Checks against the keywords present in
+ * dbus_property.json.
+ * @param[in] - record name
+ * @param[in] - keyword name
+ * @return - true if the record-keyword pair is present in dbus_property.json;
+ * false otherwise.
+ */
+bool isRecKwInDbusJson(const std::string& record, const std::string& keyword);
+
 } // namespace vpd
 } // namespace openpower
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index a20cd44..9ca68fc 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -578,7 +578,7 @@
     }
 }
 
-void EditorImpl::updateKeyword(const Binary& kwdData)
+void EditorImpl::updateKeyword(const Binary& kwdData, const bool& updCache)
 {
     startOffset = 0;
 #ifndef ManagerTest
@@ -649,9 +649,13 @@
 
             // update the ECC data for the record once data has been updated
             updateRecordECC();
+
 #ifndef ManagerTest
-            // update the cache once data has been updated
-            updateCache();
+            if (updCache)
+            {
+                // update the cache once data has been updated
+                updateCache();
+            }
 #endif
         }
         catch (const std::exception& e)
@@ -665,7 +669,6 @@
         return;
     }
 }
-
 } // namespace editor
 } // namespace manager
 } // namespace vpd
diff --git a/vpd-manager/editor_impl.hpp b/vpd-manager/editor_impl.hpp
index 9cf3b8a..96cfd07 100644
--- a/vpd-manager/editor_impl.hpp
+++ b/vpd-manager/editor_impl.hpp
@@ -75,10 +75,25 @@
     {
     }
 
+    /** @brief Construct EditorImpl class
+     *
+     * @param[in] path - EEPROM path
+     * @param[in] json - Parsed inventory json object
+     * @param[in] record - Record name
+     * @param[in] kwd - Keyword name
+     */
+    EditorImpl(const inventory::Path& path, const nlohmann::json& json,
+               const std::string& record, const std::string& kwd) :
+        vpdFilePath(path),
+        jsonFile(json), thisRecord(record, kwd)
+    {
+    }
+
     /** @brief Update data for keyword
      *  @param[in] kwdData - data to update
+     *  @param[in] updCache - Flag which tells whether to update Cache or not.
      */
-    void updateKeyword(const Binary& kwdData);
+    void updateKeyword(const Binary& kwdData, const bool& updCache);
 
     /** @brief Expands location code on DBUS
      *  @param[in] locationCodeType - "fcs" or "mts"
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index 606d3b5..5344664 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -109,7 +109,7 @@
 
         // instantiate editor class to update the data
         EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, path);
-        edit.updateKeyword(value);
+        edit.updateKeyword(value, true);
 
         // if it is a motehrboard FRU need to check for location expansion
         if (frus.find(path)->second.second)
diff --git a/vpd_tool.cpp b/vpd_tool.cpp
index e0e010a..9e76331 100644
--- a/vpd_tool.cpp
+++ b/vpd_tool.cpp
@@ -1,11 +1,16 @@
+#include "utils.hpp"
 #include "vpd_tool_impl.hpp"
 
 #include <CLI/CLI.hpp>
+#include <filesystem>
 #include <fstream>
 #include <iostream>
 
 using namespace CLI;
 using namespace std;
+namespace fs = std::filesystem;
+using namespace openpower::vpd;
+using json = nlohmann::json;
 
 int main(int argc, char** argv)
 {
@@ -17,6 +22,7 @@
     string recordName{};
     string keyword{};
     string val{};
+    string path{};
 
     auto object =
         app.add_option("--object, -O", objectPath, "Enter the Object Path");
@@ -27,6 +33,10 @@
         "--value, -V", val,
         "Enter the value. The value to be updated should be either in ascii or "
         "in hex. ascii eg: 01234; hex eg: 0x30313233");
+    auto pathOption =
+        app.add_option("--path, -P", path,
+                       "Path - if hardware option is used, give either EEPROM "
+                       "path/Object path; if not give the object path");
 
     auto dumpObjFlag =
         app.add_flag("--dumpObject, -o",
@@ -55,7 +65,7 @@
                "--writeKeyword/-w/--updateKeyword/-u "
                "--object/-O object-name --record/-R record-name --keyword/-K "
                "keyword-name --value/-V value-to-be-updated }")
-            ->needs(object)
+            ->needs(pathOption)
             ->needs(record)
             ->needs(kw)
             ->needs(valOption);
@@ -63,6 +73,12 @@
     auto forceResetFlag = app.add_flag(
         "--forceReset, -f, -F", "Force Collect for Hardware. { vpd-tool-exe "
                                 "--forceReset/-f/-F }");
+    auto Hardware = app.add_flag(
+        "--Hardware, -H",
+        "This is a supplementary flag to read/write directly from/to hardware. "
+        "Enter the hardware path while using the object option in "
+        "corresponding read/write flags. This --Hardware flag is to be given "
+        "along with readKeyword/writeKeyword.");
 
     CLI11_PARSE(app, argc, argv);
 
@@ -71,6 +87,28 @@
 
     try
     {
+        if (*Hardware)
+        {
+            if (!fs::exists(path)) // dbus object path
+            {
+                string p = getVpdFilePath(INVENTORY_JSON_SYM_LINK, path);
+                if (p.empty()) // object path not present in inventory json
+                {
+                    string errorMsg = "Invalid object path : ";
+                    errorMsg += path;
+                    errorMsg += ". Unable to find the corresponding EEPROM "
+                                "path for the given object path : ";
+                    errorMsg += path;
+                    errorMsg += " in the vpd inventory json : ";
+                    errorMsg += INVENTORY_JSON_SYM_LINK;
+                    throw runtime_error(errorMsg);
+                }
+                else
+                {
+                    path = p;
+                }
+            }
+        }
         if (*dumpObjFlag)
         {
             VpdTool vpdToolObj(move(objectPath));
@@ -90,10 +128,10 @@
             vpdToolObj.readKeyword();
         }
 
-        else if (*writeFlag)
+        else if (*writeFlag && !*Hardware)
         {
-            VpdTool vpdToolObj(move(objectPath), move(recordName),
-                               move(keyword), move(val));
+            VpdTool vpdToolObj(move(path), move(recordName), move(keyword),
+                               move(val));
             rc = vpdToolObj.updateKeyword();
         }
 
@@ -103,6 +141,13 @@
             vpdToolObj.forceReset(jsObject);
         }
 
+        else if (*writeFlag && *Hardware)
+        {
+            VpdTool vpdToolObj(move(path), move(recordName), move(keyword),
+                               move(val));
+            rc = vpdToolObj.updateHardware();
+        }
+
         else
         {
             throw runtime_error("One of the valid options is required. Refer "
diff --git a/vpd_tool_impl.cpp b/vpd_tool_impl.cpp
index 5ffb041..647bf50 100644
--- a/vpd_tool_impl.cpp
+++ b/vpd_tool_impl.cpp
@@ -1,18 +1,52 @@
 #include "vpd_tool_impl.hpp"
 
+#include "vpd_exceptions.hpp"
+
 #include <cstdlib>
 #include <filesystem>
-#include <iomanip>
 #include <iostream>
 #include <sdbusplus/bus.hpp>
-#include <sstream>
 #include <variant>
 #include <vector>
 
 using namespace std;
 using sdbusplus::exception::SdBusError;
 using namespace openpower::vpd;
+using namespace inventory;
+using namespace openpower::vpd::manager::editor;
 namespace fs = std::filesystem;
+using json = nlohmann::json;
+using namespace openpower::vpd::exceptions;
+
+Binary VpdTool::toBinary(const std::string& value)
+{
+    Binary val{};
+    if (value.find("0x") == string::npos)
+    {
+        val.assign(value.begin(), value.end());
+    }
+    else if (value.find("0x") != string::npos)
+    {
+        stringstream ss;
+        ss.str(value.substr(2));
+        string byteStr{};
+
+        while (!ss.eof())
+        {
+            ss >> setw(2) >> byteStr;
+            uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
+
+            val.push_back(byte);
+        }
+    }
+
+    else
+    {
+        throw runtime_error("The value to be updated should be either in ascii "
+                            "or in hex. Refer --help option");
+    }
+    return val;
+}
 
 void VpdTool::printReturnCode(int returnCode)
 {
@@ -351,35 +385,7 @@
 
 int VpdTool::updateKeyword()
 {
-    Binary val;
-
-    if (value.find("0x") == string::npos)
-    {
-        val.assign(value.begin(), value.end());
-    }
-    else if (value.find("0x") != string::npos)
-    {
-        stringstream ss;
-        ss.str(value.substr(2));
-        string byteStr{};
-
-        while (!ss.eof())
-        {
-            ss >> setw(2) >> byteStr;
-            uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
-
-            val.push_back(byte);
-        }
-    }
-
-    else
-    {
-        throw runtime_error("The value to be updated should be either in ascii "
-                            "or in hex. Refer --help option");
-    }
-
-    // writeKeyword(fruPath, recordName, keyword, val);
-
+    Binary val = toBinary(value);
     auto bus = sdbusplus::bus::new_default();
     auto properties =
         bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
@@ -442,3 +448,27 @@
     returnCode = system(udevAdd.c_str());
     printReturnCode(returnCode);
 }
+
+int VpdTool::updateHardware()
+{
+    int rc = 0;
+    bool updCache = true;
+    const Binary& val = static_cast<const Binary&>(toBinary(value));
+    ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
+    try
+    {
+        auto json = nlohmann::json::parse(inventoryJson);
+        EditorImpl edit(fruPath, json, recordName, keyword);
+        if (!((isPathInJson(fruPath)) &&
+              (isRecKwInDbusJson(recordName, keyword))))
+        {
+            updCache = false;
+        }
+        edit.updateKeyword(val, updCache);
+    }
+    catch (json::parse_error& ex)
+    {
+        throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
+    }
+    return rc;
+}
diff --git a/vpd_tool_impl.hpp b/vpd_tool_impl.hpp
index b490fcc..1ca50b5 100644
--- a/vpd_tool_impl.hpp
+++ b/vpd_tool_impl.hpp
@@ -1,6 +1,8 @@
 #include "config.h"
 
+#include "editor_impl.hpp"
 #include "types.hpp"
+#include "utils.hpp"
 
 #include <nlohmann/json.hpp>
 #include <string>
@@ -118,9 +120,22 @@
      */
     void eraseInventoryPath(std::string& fru);
 
-    /** @brief printReturnCode */
+    /**
+     * @brief printReturnCode
+     * Prints the return code of the program in console output, whenever
+     * the program fails to exit successfully.
+     *
+     * @param[in] returnCode - return code of the program.
+     */
     void printReturnCode(int returnCode);
 
+    /**
+     * @brief Convert hex/ascii values to Binary
+     * @param[in] - value in hex/ascii.
+     * @param[out] - value in binary.
+     */
+    openpower::vpd::Binary toBinary(const std::string& value);
+
   public:
     /**
      * @brief Dump the complete inventory in JSON format
@@ -166,13 +181,22 @@
      * @brief Get Printable Value
      *
      * Checks if the vector value has non printable characters.
-     * And returns hex value if non printable char is found else
+     * Returns hex value if non printable char is found else
      * returns ascii value.
      *
      * @param[in] vector - Reference of the Binary vector
      * @return printable value - either in hex or in ascii.
      */
-    std::string getPrintableValue(const std::vector<unsigned char>& vec);
+    std::string getPrintableValue(const std::vector<unsigned char>& vector);
+
+    /**
+     * @brief Update Hardware
+     * If the given record-keyword pair is present in dbus_properties.json,
+     * then will update the given data in both dbus and hardware.
+     * Else update the given data only in hardware.
+     * @return returncode (success/failure).
+     */
+    int updateHardware();
 
     /**
      * @brief Constructor