Vpd-tool:Read keyword from hardware

Vpd-tool adds an option to read any keyword
directly from hardware with the help of -H option.

This commit has the front-end portion which gets the
user option and calls the back end code which is present
in Impl class in this commit
https://gerrit.openbmc.org/c/openbmc/openpower-vpd-parser/+/47666 .

Test:
Tested on rainier.

1.
root@rain111bmc:/tmp# ./vpd-tool -r -O /sys/bus/spi/drivers/at25/spi12.0/eeprom -R CP00 -K PG -H
{
    "/sys/bus/spi/drivers/at25/spi12.0/eeprom": {
        "PG": "0x01e03fffe051ffe37fffe53fffffffffffffffffffffffffffe00c1fe00c1fffffffffffffe21dffe21dffffffffffffffe79fffe39fffe79fffe79fffffffffffffffffffffffffffffffffffffffe3bdffe3bdffe3bdffffffffe3bdffe3bdffe7f9ffe1987fe0001fe7f9ffe7f9ffe0001fe6619fe0001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
    }
}

root@rain111bmc:/tmp# ./vpd-tool -r -O /system/chassis/motherboard/dcm0/cpu0 -R CP00 -K PG
{
    "/system/chassis/motherboard/dcm0/cpu0": {
        "PG": "0x01e03fffe051ffe37fffe53fffffffffffffffffffffffffffe00c1fe00c1fffffffffffffe21dffe21dffffffffffffffe79fffe39fffe79fffe79fffffffffffffffffffffffffffffffffffffffe3bdffe3bdffe3bdffffffffe3bdffe3bdffe7f9ffe1987fe0001fe7f9ffe7f9ffe0001fe6619fe0001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
    }
}

2.
root@rain111bmc:/tmp# ./vpd-tool -r -H -O /sys/bus/spi/drivers/at25/spi12.0/eeprom -R VINI -K SN
{
    "/sys/bus/spi/drivers/at25/spi12.0/eeprom": {
        "SN": "YA3936110110"
    }
}
root@rain111bmc:/tmp# ./vpd-tool -r -O /system/chassis/motherboard/dcm0/cpu0 -R VINI -K SN
{
    "/system/chassis/motherboard/dcm0/cpu0": {
        "SN": "YA3936110110"
    }
}

3.
root@rain111bmc:/tmp# ./vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R VSYS -K BR
{
    "/sys/bus/i2c/drivers/at24/8-0050/eeprom": {
        "BR": "S0"
    }
}

4.
root@rain111bmc:/tmp# ./vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R VINI -K SN
{
    "/sys/bus/i2c/drivers/at24/8-0050/eeprom": {
        "SN": "Y131UF07302S"
    }
}

5.
root@perfrain86bmctest:/tmp# ./vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/7-0050/eeprom -R VR10 -K BD
The given keyword BD is not present in the given record VR10 in the given vpd path /sys/bus/i2c/drivers/at24/7-0050/eeprom

6.
root@perfrain86bmctest:/tmp# ./vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/7-0050/eeprom -R CP00 -K SN
The given record CP00 is not present in the given vpd path /sys/bus/i2c/drivers/at24/7-0050/eeprom

7.
root@perfrain86bmctest:/tmp# ./vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/7-0050/eeprom -R VR10 -K DC
{
    "/sys/bus/i2c/drivers/at24/7-0050/eeprom": {
        "DC": "BD 201908260800"
    }
}

Signed-off-by: Priyanga Ramasamy <priyanga24@in.ibm.com>
Change-Id: I37f85fe22a2c98704bbc8f6090f0d83084d4c6f8
diff --git a/meson.build b/meson.build
index 304c4c9..31a11d4 100644
--- a/meson.build
+++ b/meson.build
@@ -149,7 +149,8 @@
                                    ],
                                  link_with : libvpdecc,
                                  install: true,
-                                 include_directories : vpd_tool_INCLUDE
+                                 include_directories : vpd_tool_INCLUDE,
+                                 cpp_args : '-DIPZ_PARSER'
                                  )
 if get_option('vpd-manager').enabled()
     subdir('vpd-manager')
diff --git a/vpd_tool.cpp b/vpd_tool.cpp
index 92ab4e0..74c12ac 100644
--- a/vpd_tool.cpp
+++ b/vpd_tool.cpp
@@ -104,7 +104,7 @@
             vpdToolObj.dumpInventory(jsObject);
         }
 
-        else if (*readFlag)
+        else if (*readFlag && !*Hardware)
         {
             VpdTool vpdToolObj(move(objectPath), move(recordName),
                                move(keyword));
@@ -141,7 +141,12 @@
                                move(keyword), move(val));
             rc = vpdToolObj.updateHardware();
         }
-
+        else if (*readFlag && *Hardware)
+        {
+            VpdTool vpdToolObj(move(objectPath), move(recordName),
+                               move(keyword));
+            vpdToolObj.readKwFromHw();
+        }
         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 9232121..2d777e9 100644
--- a/vpd_tool_impl.cpp
+++ b/vpd_tool_impl.cpp
@@ -1,5 +1,6 @@
 #include "vpd_tool_impl.hpp"
 
+#include "impl.hpp"
 #include "vpd_exceptions.hpp"
 
 #include <cstdlib>
@@ -16,6 +17,7 @@
 namespace fs = std::filesystem;
 using json = nlohmann::json;
 using namespace openpower::vpd::exceptions;
+using namespace openpower::vpd::parser;
 
 Binary VpdTool::toBinary(const std::string& value)
 {
@@ -515,4 +517,56 @@
         throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
     }
     return rc;
-}
\ No newline at end of file
+}
+
+void VpdTool::readKwFromHw()
+{
+    uint32_t startOffset = 0;
+
+    ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
+    auto jsonFile = nlohmann::json::parse(inventoryJson);
+
+    for (const auto& item : jsonFile["frus"][fruPath])
+    {
+        if (item.find("offset") != item.end())
+        {
+            startOffset = item["offset"];
+        }
+    }
+
+    Binary completeVPDFile;
+    completeVPDFile.resize(65504);
+    fstream vpdFileStream;
+    vpdFileStream.open(fruPath,
+                       std::ios::in | std::ios::out | std::ios::binary);
+
+    vpdFileStream.seekg(startOffset, ios_base::cur);
+    vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]), 65504);
+    completeVPDFile.resize(vpdFileStream.gcount());
+    vpdFileStream.clear(std::ios_base::eofbit);
+
+    if (completeVPDFile.empty())
+    {
+        throw std::runtime_error("Invalid File");
+    }
+    Impl obj(completeVPDFile);
+    std::string keywordVal = obj.readKwFromHw(recordName, keyword);
+
+    if (!keywordVal.empty())
+    {
+        json output = json::object({});
+        json kwVal = json::object({});
+        kwVal.emplace(keyword, keywordVal);
+
+        output.emplace(fruPath, kwVal);
+
+        debugger(output);
+    }
+    else
+    {
+        std::cerr << "The given keyword " << keyword << " or record "
+                  << recordName
+                  << " or both are not present in the given FRU path "
+                  << fruPath << std::endl;
+    }
+}
diff --git a/vpd_tool_impl.hpp b/vpd_tool_impl.hpp
index 5ae9284..8b1207d 100644
--- a/vpd_tool_impl.hpp
+++ b/vpd_tool_impl.hpp
@@ -183,6 +183,14 @@
     int updateHardware();
 
     /**
+     * @brief Read Keyword from Hardware
+     * This api is to read a keyword directly from the hardware. The hardware
+     * path, record name and keyword name are received at the time of
+     * initialising the constructor.
+     */
+    void readKwFromHw();
+
+    /**
      * @brief Constructor
      * Constructor is called during the
      * object instantiation for dumpInventory option and