Rename tool/ as pldmtool/

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I38d7a6ab907014cd5fca049b095d692d069feab1
diff --git a/pldmtool/meson.build b/pldmtool/meson.build
new file mode 100644
index 0000000..48f4c26
--- /dev/null
+++ b/pldmtool/meson.build
@@ -0,0 +1,25 @@
+libpldm_headers = ['.', './oem/ibm']
+
+sources = [
+  'pldm_cmd_helper.cpp',
+  'pldm_base_cmd.cpp',
+  'pldm_platform_cmd.cpp',
+  'pldm_bios_cmd.cpp',
+  'pldm_fru_cmd.cpp',
+  'pldmtool.cpp',
+]
+
+if get_option('oem-ibm').enabled()
+sources += [
+    'oem/ibm/pldm_host_cmd.cpp'
+  ]
+endif
+
+executable(
+  'pldmtool',
+  sources,
+  implicit_include_directories: false,
+  include_directories: include_directories(libpldm_headers),
+  dependencies: [libpldm, libpldmutils, dependency('sdbusplus')],
+  install: true,
+  install_dir: get_option('bindir'))
diff --git a/pldmtool/oem/ibm/pldm_host_cmd.cpp b/pldmtool/oem/ibm/pldm_host_cmd.cpp
new file mode 100644
index 0000000..4f14e8c
--- /dev/null
+++ b/pldmtool/oem/ibm/pldm_host_cmd.cpp
@@ -0,0 +1,87 @@
+#include "pldm_host_cmd.hpp"
+
+#include "oem/ibm/libpldm/host.h"
+
+#include "../../pldm_cmd_helper.hpp"
+
+namespace pldmtool
+{
+
+namespace oem_ibm
+{
+namespace power_host
+{
+using namespace pldmtool::helper;
+
+std::vector<std::unique_ptr<CommandInterface>> commands;
+
+class GetAlertStatus : public CommandInterface
+{
+  public:
+    ~GetAlertStatus() = default;
+    GetAlertStatus() = delete;
+    GetAlertStatus(const GetAlertStatus&) = delete;
+    GetAlertStatus(GetAlertStatus&&) = default;
+    GetAlertStatus& operator=(const GetAlertStatus&) = delete;
+    GetAlertStatus& operator=(GetAlertStatus&&) = default;
+
+    explicit GetAlertStatus(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option(
+               "-i, --id", versionId,
+               "Version of the command/response format. 0x00 for this format")
+            ->required();
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_ALERT_STATUS_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_alert_status_req(instanceId, versionId, request,
+                                              PLDM_GET_ALERT_STATUS_REQ_BYTES);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t completionCode = 0;
+        uint32_t rack_entry = 0;
+        uint32_t pri_cec_node = 0;
+        auto rc = decode_get_alert_status_resp(responsePtr, payloadLength,
+                                               &completionCode, &rack_entry,
+                                               &pri_cec_node);
+
+        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
+            return;
+        }
+
+        std::cout << "GetAlertStatus Success: " << std::endl;
+        std::cout << "rack entry: 0x" << std::setfill('0') << std::setw(8)
+                  << std::hex << (int)rack_entry << std::endl;
+        std::cout << "pri cec node: 0x" << std::setfill('0') << std::setw(8)
+                  << std::hex << (int)pri_cec_node << std::endl;
+    }
+
+  private:
+    uint8_t versionId;
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto oem_ibm = app.add_subcommand("oem-ibm", "oem type command");
+    oem_ibm->require_subcommand(1);
+
+    auto getAlertStatus = oem_ibm->add_subcommand(
+        "GetAlertStatus", "get alert status descriptor");
+    commands.push_back(std::make_unique<GetAlertStatus>(
+        "oem_ibm", "getAlertStatus", getAlertStatus));
+}
+} // namespace power_host
+} // namespace oem_ibm
+} // namespace pldmtool
diff --git a/pldmtool/oem/ibm/pldm_host_cmd.hpp b/pldmtool/oem/ibm/pldm_host_cmd.hpp
new file mode 100644
index 0000000..d57ccd4
--- /dev/null
+++ b/pldmtool/oem/ibm/pldm_host_cmd.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <CLI/CLI.hpp>
+
+namespace pldmtool
+{
+
+namespace oem_ibm
+{
+namespace power_host
+{
+
+void registerCommand(CLI::App& app);
+
+}
+
+} // namespace oem_ibm
+
+} // namespace pldmtool
diff --git a/pldmtool/pldm_base_cmd.cpp b/pldmtool/pldm_base_cmd.cpp
new file mode 100644
index 0000000..8079850
--- /dev/null
+++ b/pldmtool/pldm_base_cmd.cpp
@@ -0,0 +1,356 @@
+#include "pldm_base_cmd.hpp"
+
+#include "libpldm/utils.h"
+
+#include "pldm_cmd_helper.hpp"
+
+#ifdef OEM_IBM
+#include "libpldm/file_io.h"
+#include "libpldm/host.h"
+#endif
+
+namespace pldmtool
+{
+
+namespace base
+{
+
+namespace
+{
+
+using namespace pldmtool::helper;
+
+std::vector<std::unique_ptr<CommandInterface>> commands;
+const std::map<const char*, pldm_supported_types> pldmTypes{
+    {"base", PLDM_BASE},   {"platform", PLDM_PLATFORM},
+    {"bios", PLDM_BIOS},   {"fru", PLDM_FRU},
+#ifdef OEM_IBM
+    {"oem-ibm", PLDM_OEM},
+#endif
+};
+
+const std::map<const char*, pldm_supported_commands> pldmBaseCmds{
+    {"GetTID", PLDM_GET_TID},
+    {"GetPLDMVersion", PLDM_GET_PLDM_VERSION},
+    {"GetPLDMTypes", PLDM_GET_PLDM_TYPES},
+    {"GetPLDMCommands", PLDM_GET_PLDM_COMMANDS}};
+
+const std::map<const char*, pldm_bios_commands> pldmBiosCmds{
+    {"GetBIOSTable", PLDM_GET_BIOS_TABLE},
+    {"SetBIOSAttributeCurrentValue", PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE},
+    {"GetBIOSAttributeCurrentValueByHandle",
+     PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE},
+    {"GetDateTime", PLDM_GET_DATE_TIME},
+    {"SetDateTime", PLDM_SET_DATE_TIME}};
+
+const std::map<const char*, pldm_platform_commands> pldmPlatformCmds{
+    {"SetNumericEffecterValue", PLDM_SET_NUMERIC_EFFECTER_VALUE},
+    {"SetStateEffecterStates", PLDM_SET_STATE_EFFECTER_STATES},
+    {"GetPDR", PLDM_GET_PDR}};
+
+const std::map<const char*, pldm_fru_commands> pldmFruCmds{
+    {"GetFRURecordTableMetadata", PLDM_GET_FRU_RECORD_TABLE_METADATA},
+    {"GetFRURecordTable", PLDM_GET_FRU_RECORD_TABLE}};
+
+#ifdef OEM_IBM
+const std::map<const char*, pldm_host_commands> pldmIBMHostCmds{
+    {"GetAlertStatus", PLDM_HOST_GET_ALERT_STATUS}};
+
+const std::map<const char*, pldm_fileio_commands> pldmIBMFileIOCmds{
+    {"GetFileTable", PLDM_GET_FILE_TABLE},
+    {"ReadFile", PLDM_READ_FILE},
+    {"WriteFile", PLDM_WRITE_FILE},
+    {"ReadFileInToMemory", PLDM_READ_FILE_INTO_MEMORY},
+    {"WriteFileFromMemory", PLDM_WRITE_FILE_FROM_MEMORY},
+    {"ReadFileByTypeIntoMemory", PLDM_READ_FILE_BY_TYPE_INTO_MEMORY},
+    {"WriteFileByTypeFromMemory", PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY},
+    {"NewFileAvailable", PLDM_NEW_FILE_AVAILABLE},
+    {"ReadFileByType", PLDM_READ_FILE_BY_TYPE},
+    {"WriteFileByType", PLDM_WRITE_FILE_BY_TYPE},
+    {"FileAck", PLDM_FILE_ACK}};
+#endif
+
+} // namespace
+
+class GetPLDMTypes : public CommandInterface
+{
+  public:
+    ~GetPLDMTypes() = default;
+    GetPLDMTypes() = delete;
+    GetPLDMTypes(const GetPLDMTypes&) = delete;
+    GetPLDMTypes(GetPLDMTypes&&) = default;
+    GetPLDMTypes& operator=(const GetPLDMTypes&) = delete;
+    GetPLDMTypes& operator=(GetPLDMTypes&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+        auto rc = encode_get_types_req(instanceId, request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0;
+        std::vector<bitfield8_t> types(8);
+        auto rc = decode_get_types_resp(responsePtr, payloadLength, &cc,
+                                        types.data());
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << "\n";
+            return;
+        }
+
+        printPldmTypes(types);
+    }
+
+  private:
+    void printPldmTypes(std::vector<bitfield8_t>& types)
+    {
+        std::cout << "Supported types:";
+        for (int i = 0; i < PLDM_MAX_TYPES; i++)
+        {
+            bitfield8_t b = types[i / 8];
+            if (b.byte & (1 << i % 8))
+            {
+                std::cout << " " << i;
+                auto it = std::find_if(
+                    pldmTypes.begin(), pldmTypes.end(),
+                    [i](const auto& typePair) { return typePair.second == i; });
+                if (it != pldmTypes.end())
+                {
+
+                    std::cout << "(" << it->first << ")";
+                }
+            }
+        }
+
+        std::cout << std::endl;
+    }
+};
+
+class GetPLDMVersion : public CommandInterface
+{
+  public:
+    ~GetPLDMVersion() = default;
+    GetPLDMVersion() = delete;
+    GetPLDMVersion(const GetPLDMVersion&) = delete;
+    GetPLDMVersion(GetPLDMVersion&&) = default;
+    GetPLDMVersion& operator=(const GetPLDMVersion&) = delete;
+    GetPLDMVersion& operator=(GetPLDMVersion&&) = default;
+
+    explicit GetPLDMVersion(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option("-t,--type", pldmType, "pldm supported type")
+            ->required()
+            ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
+    }
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_VERSION_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART,
+                                         pldmType, request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0, transferFlag = 0;
+        uint32_t transferHandle = 0;
+        ver32_t version;
+        auto rc =
+            decode_get_version_resp(responsePtr, payloadLength, &cc,
+                                    &transferHandle, &transferFlag, &version);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << "\n";
+            return;
+        }
+        char buffer[16] = {0};
+        ver2str(&version, buffer, sizeof(buffer));
+        std::cout << "Type " << pldmType;
+        auto it = std::find_if(
+            pldmTypes.begin(), pldmTypes.end(),
+            [&](const auto& typePair) { return typePair.second == pldmType; });
+
+        if (it != pldmTypes.end())
+        {
+            std::cout << "(" << it->first << ")";
+        }
+        std::cout << ": " << buffer << std::endl;
+    }
+
+  private:
+    pldm_supported_types pldmType;
+};
+
+class GetTID : public CommandInterface
+{
+  public:
+    ~GetTID() = default;
+    GetTID() = delete;
+    GetTID(const GetTID&) = delete;
+    GetTID(GetTID&&) = default;
+    GetTID& operator=(const GetTID&) = delete;
+    GetTID& operator=(GetTID&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+        auto rc = encode_get_tid_req(instanceId, request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0;
+        uint8_t tid = 0;
+        std::vector<bitfield8_t> types(8);
+        auto rc = decode_get_tid_resp(responsePtr, payloadLength, &cc, &tid);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << "\n";
+            return;
+        }
+        std::cout << "TID : " << static_cast<uint32_t>(tid) << std::endl;
+    }
+};
+
+class GetPLDMCommands : public CommandInterface
+{
+  public:
+    ~GetPLDMCommands() = default;
+    GetPLDMCommands() = delete;
+    GetPLDMCommands(const GetPLDMCommands&) = delete;
+    GetPLDMCommands(GetPLDMCommands&&) = default;
+    GetPLDMCommands& operator=(const GetPLDMCommands&) = delete;
+    GetPLDMCommands& operator=(GetPLDMCommands&&) = default;
+
+    explicit GetPLDMCommands(const char* type, const char* name,
+                             CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option("-t,--type", pldmType, "pldm supported type")
+            ->required()
+            ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_COMMANDS_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+        ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
+        auto rc =
+            encode_get_commands_req(instanceId, pldmType, version, request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0;
+        std::vector<bitfield8_t> cmdTypes(32);
+        auto rc = decode_get_commands_resp(responsePtr, payloadLength, &cc,
+                                           cmdTypes.data());
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << "\n";
+            return;
+        }
+        printPldmCommands(cmdTypes, pldmType);
+    }
+
+  private:
+    pldm_supported_types pldmType;
+
+    template <typename CommandMap>
+    void printCommand(CommandMap& commandMap, int i)
+    {
+        auto it = std::find_if(
+            commandMap.begin(), commandMap.end(),
+            [i](const auto& typePair) { return typePair.second == i; });
+        if (it != commandMap.end())
+        {
+            std::cout << "(" << it->first << ")";
+        }
+    }
+
+    void printPldmCommands(std::vector<bitfield8_t>& cmdTypes,
+                           pldm_supported_types pldmType)
+    {
+        std::cout << "Supported Commands :";
+        for (int i = 0; i < PLDM_MAX_CMDS_PER_TYPE; i++)
+        {
+            bitfield8_t b = cmdTypes[i / 8];
+            if (b.byte & (1 << i % 8))
+            {
+                std::cout << " " << i;
+                switch (pldmType)
+                {
+                    case PLDM_BASE:
+                        printCommand(pldmBaseCmds, i);
+                        break;
+                    case PLDM_PLATFORM:
+                        printCommand(pldmPlatformCmds, i);
+                        break;
+                    case PLDM_BIOS:
+                        printCommand(pldmBiosCmds, i);
+                        break;
+                    case PLDM_FRU:
+                        printCommand(pldmFruCmds, i);
+                        break;
+                    case PLDM_OEM:
+#ifdef OEM_IBM
+                        printCommand(pldmIBMHostCmds, i);
+                        printCommand(pldmIBMFileIOCmds, i);
+#endif
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        std::cout << std::endl;
+    }
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto base = app.add_subcommand("base", "base type command");
+    base->require_subcommand(1);
+
+    auto getPLDMTypes =
+        base->add_subcommand("GetPLDMTypes", "get pldm supported types");
+    commands.push_back(
+        std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
+
+    auto getPLDMVersion =
+        base->add_subcommand("GetPLDMVersion", "get version of a certain type");
+    commands.push_back(std::make_unique<GetPLDMVersion>(
+        "base", "GetPLDMVersion", getPLDMVersion));
+
+    auto getPLDMTID = base->add_subcommand("GetTID", "get Terminus ID (TID)");
+    commands.push_back(std::make_unique<GetTID>("base", "GetTID", getPLDMTID));
+
+    auto getPLDMCommands = base->add_subcommand(
+        "GetPLDMCommands", "get supported commands of pldm type");
+    commands.push_back(std::make_unique<GetPLDMCommands>(
+        "base", "GetPLDMCommands", getPLDMCommands));
+}
+
+} // namespace base
+} // namespace pldmtool
diff --git a/pldmtool/pldm_base_cmd.hpp b/pldmtool/pldm_base_cmd.hpp
new file mode 100644
index 0000000..2e8056d
--- /dev/null
+++ b/pldmtool/pldm_base_cmd.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <CLI/CLI.hpp>
+
+namespace pldmtool
+{
+
+namespace base
+{
+
+void registerCommand(CLI::App& app);
+}
+
+} // namespace pldmtool
diff --git a/pldmtool/pldm_bios_cmd.cpp b/pldmtool/pldm_bios_cmd.cpp
new file mode 100644
index 0000000..ba40dea
--- /dev/null
+++ b/pldmtool/pldm_bios_cmd.cpp
@@ -0,0 +1,949 @@
+#include "pldm_bios_cmd.hpp"
+
+#include "libpldm/bios_table.h"
+#include "libpldm/utils.h"
+
+#include "common/bios_utils.hpp"
+#include "common/utils.hpp"
+#include "pldm_cmd_helper.hpp"
+
+#include <map>
+#include <optional>
+
+namespace pldmtool
+{
+
+namespace bios
+{
+
+namespace
+{
+
+using namespace pldmtool::helper;
+using namespace pldm::bios::utils;
+
+std::vector<std::unique_ptr<CommandInterface>> commands;
+
+const std::map<const char*, pldm_bios_table_types> pldmBIOSTableTypes{
+    {"StringTable", PLDM_BIOS_STRING_TABLE},
+    {"AttributeTable", PLDM_BIOS_ATTR_TABLE},
+    {"AttributeValueTable", PLDM_BIOS_ATTR_VAL_TABLE},
+};
+
+} // namespace
+
+class GetDateTime : public CommandInterface
+{
+  public:
+    ~GetDateTime() = default;
+    GetDateTime() = delete;
+    GetDateTime(const GetDateTime&) = delete;
+    GetDateTime(GetDateTime&&) = default;
+    GetDateTime& operator=(const GetDateTime&) = delete;
+    GetDateTime& operator=(GetDateTime&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_date_time_req(instanceId, request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0;
+
+        uint8_t seconds, minutes, hours, day, month;
+        uint16_t year;
+        auto rc =
+            decode_get_date_time_resp(responsePtr, payloadLength, &cc, &seconds,
+                                      &minutes, &hours, &day, &month, &year);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+            return;
+        }
+        std::cout << "Date & Time : " << std::endl;
+        std::cout << "YYYY-MM-DD HH:MM:SS - ";
+        std::cout << bcd2dec16(year);
+        std::cout << "-";
+        setWidth(month);
+        std::cout << "-";
+        setWidth(day);
+        std::cout << " ";
+        setWidth(hours);
+        std::cout << ":";
+        setWidth(minutes);
+        std::cout << ":";
+        setWidth(seconds);
+        std::cout << std::endl;
+    }
+
+  private:
+    void setWidth(uint8_t data)
+    {
+        std::cout << std::setfill('0') << std::setw(2)
+                  << static_cast<uint32_t>(bcd2dec8(data));
+    }
+};
+
+class SetDateTime : public CommandInterface
+{
+  public:
+    ~SetDateTime() = default;
+    SetDateTime() = delete;
+    SetDateTime(const SetDateTime&) = delete;
+    SetDateTime(SetDateTime&&) = default;
+    SetDateTime& operator=(const SetDateTime&) = delete;
+    SetDateTime& operator=(SetDateTime&&) = default;
+
+    explicit SetDateTime(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option("-d,--data", tmData,
+                        "set date time data\n"
+                        "eg: YYYYMMDDHHMMSS")
+            ->required();
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        sizeof(struct pldm_set_date_time_req));
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+        uint16_t year = 0;
+        uint8_t month = 0;
+        uint8_t day = 0;
+        uint8_t hours = 0;
+        uint8_t minutes = 0;
+        uint8_t seconds = 0;
+
+        if (!uintToDate(tmData, &year, &month, &day, &hours, &minutes,
+                        &seconds))
+        {
+            std::cerr << "decode date Error: "
+                      << "tmData=" << tmData << std::endl;
+
+            return {PLDM_ERROR_INVALID_DATA, requestMsg};
+        }
+
+        auto rc = encode_set_date_time_req(
+            instanceId, seconds, minutes, hours, day, month, year, request,
+            sizeof(struct pldm_set_date_time_req));
+
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t completionCode = 0;
+        auto rc = decode_set_date_time_resp(responsePtr, payloadLength,
+                                            &completionCode);
+
+        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)completionCode
+                      << std::endl;
+            return;
+        }
+
+        std::cout << "SetDateTime: SUCCESS" << std::endl;
+    }
+
+  private:
+    uint64_t tmData;
+};
+
+class GetBIOSTableHandler : public CommandInterface
+{
+  public:
+    ~GetBIOSTableHandler() = default;
+    GetBIOSTableHandler() = delete;
+    GetBIOSTableHandler(const GetBIOSTableHandler&) = delete;
+    GetBIOSTableHandler(GetBIOSTableHandler&&) = delete;
+    GetBIOSTableHandler& operator=(const GetBIOSTableHandler&) = delete;
+    GetBIOSTableHandler& operator=(GetBIOSTableHandler&&) = delete;
+
+    using Table = std::vector<uint8_t>;
+
+    using CommandInterface::CommandInterface;
+
+    static inline const std::map<pldm_bios_attribute_type, const char*>
+        attrTypeMap = {
+            {PLDM_BIOS_ENUMERATION, "BIOSEnumeration"},
+            {PLDM_BIOS_ENUMERATION_READ_ONLY, "BIOSEnumerationReadOnly"},
+            {PLDM_BIOS_STRING, "BIOSString"},
+            {PLDM_BIOS_STRING_READ_ONLY, "BIOSStringReadOnly"},
+            {PLDM_BIOS_PASSWORD, "BIOSPassword"},
+            {PLDM_BIOS_PASSWORD_READ_ONLY, "BIOSPasswordReadOnly"},
+            {PLDM_BIOS_INTEGER, "BIOSInteger"},
+            {PLDM_BIOS_INTEGER_READ_ONLY, "BIOSIntegerReadOnly"},
+
+        };
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        return {PLDM_ERROR, {}};
+    }
+
+    void parseResponseMsg(pldm_msg*, size_t) override
+    {}
+
+    std::optional<Table> getBIOSTable(pldm_bios_table_types tableType)
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_BIOS_TABLE_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_bios_table_req(instanceId, 0, PLDM_GET_FIRSTPART,
+                                            tableType, request);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "Encode GetBIOSTable Error, tableType=," << tableType
+                      << " ,rc=" << rc << std::endl;
+            return std::nullopt;
+        }
+        std::vector<uint8_t> responseMsg;
+        rc = pldmSendRecv(requestMsg, responseMsg);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
+            return std::nullopt;
+        }
+
+        uint8_t cc = 0, transferFlag = 0;
+        uint32_t nextTransferHandle = 0;
+        size_t bios_table_offset;
+        auto responsePtr =
+            reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+        auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
+
+        rc = decode_get_bios_table_resp(responsePtr, payloadLength, &cc,
+                                        &nextTransferHandle, &transferFlag,
+                                        &bios_table_offset);
+
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "GetBIOSTable Response Error: tableType=" << tableType
+                      << ", rc=" << rc << ", cc=" << (int)cc << std::endl;
+            return std::nullopt;
+        }
+        auto tableData =
+            reinterpret_cast<char*>((responsePtr->payload) + bios_table_offset);
+        auto tableSize = payloadLength - sizeof(nextTransferHandle) -
+                         sizeof(transferFlag) - sizeof(cc);
+        return std::make_optional<Table>(tableData, tableData + tableSize);
+    }
+
+    const pldm_bios_attr_table_entry*
+        findAttrEntryByName(const std::string& name, const Table& attrTable,
+                            const Table& stringTable)
+    {
+        auto stringEntry = pldm_bios_table_string_find_by_string(
+            stringTable.data(), stringTable.size(), name.c_str());
+        if (stringEntry == nullptr)
+        {
+            return nullptr;
+        }
+
+        auto nameHandle =
+            pldm_bios_table_string_entry_decode_handle(stringEntry);
+
+        for (auto attr : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable.data(),
+                                                             attrTable.size()))
+        {
+            auto attrNameHandle =
+                pldm_bios_table_attr_entry_decode_string_handle(attr);
+            if (attrNameHandle == nameHandle)
+            {
+                return attr;
+            }
+        }
+        return nullptr;
+    }
+
+    std::optional<uint16_t> findAttrHandleByName(const std::string& name,
+                                                 const Table& attrTable,
+                                                 const Table& stringTable)
+    {
+        auto attribute = findAttrEntryByName(name, attrTable, stringTable);
+        if (attribute == nullptr)
+        {
+            return std::nullopt;
+        }
+
+        return pldm_bios_table_attr_entry_decode_attribute_handle(attribute);
+    }
+
+    std::string decodeStringFromStringEntry(
+        const pldm_bios_string_table_entry* stringEntry)
+    {
+        auto strLength =
+            pldm_bios_table_string_entry_decode_string_length(stringEntry);
+        std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
+        pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
+                                                   buffer.size());
+
+        return std::string(buffer.data(), buffer.data() + strLength);
+    }
+
+    std::string displayStringHandle(uint16_t handle,
+                                    const std::optional<Table>& stringTable,
+                                    bool displayHandle = true)
+    {
+        std::string displayString = std::to_string(handle);
+        if (!stringTable)
+        {
+            return displayString;
+        }
+        auto stringEntry = pldm_bios_table_string_find_by_handle(
+            stringTable->data(), stringTable->size(), handle);
+        if (stringEntry == nullptr)
+        {
+            return displayString;
+        }
+
+        auto decodedStr = decodeStringFromStringEntry(stringEntry);
+        if (!displayHandle)
+        {
+            return decodedStr;
+        }
+
+        return displayString + "(" + decodedStr + ")";
+    }
+
+    std::string displayEnumValueByIndex(uint16_t attrHandle, uint8_t index,
+                                        const std::optional<Table>& attrTable,
+                                        const std::optional<Table>& stringTable)
+    {
+        std::string displayString;
+        if (!attrTable)
+        {
+            return displayString;
+        }
+
+        auto attrEntry = pldm_bios_table_attr_find_by_handle(
+            attrTable->data(), attrTable->size(), attrHandle);
+        if (attrEntry == nullptr)
+        {
+            return displayString;
+        }
+        auto pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
+        std::vector<uint16_t> pvHandls(pvNum);
+        pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+            attrEntry, pvHandls.data(), pvHandls.size());
+        return displayStringHandle(pvHandls[index], stringTable, false);
+    }
+
+    void displayAttributeValueEntry(
+        const pldm_bios_attr_val_table_entry* tableEntry,
+        const std::optional<Table>& attrTable,
+        const std::optional<Table>& stringTable, bool verbose)
+    {
+        auto attrHandle =
+            pldm_bios_table_attr_value_entry_decode_attribute_handle(
+                tableEntry);
+        auto attrType = static_cast<pldm_bios_attribute_type>(
+            pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
+        if (verbose)
+        {
+            std::cout << "AttributeHandle: " << attrHandle << std::endl;
+            std::cout << "\tAttributeType: " << attrTypeMap.at(attrType)
+                      << std::endl;
+        }
+        switch (attrType)
+        {
+            case PLDM_BIOS_ENUMERATION:
+            case PLDM_BIOS_ENUMERATION_READ_ONLY:
+            {
+                auto count =
+                    pldm_bios_table_attr_value_entry_enum_decode_number(
+                        tableEntry);
+                std::vector<uint8_t> handles(count);
+                pldm_bios_table_attr_value_entry_enum_decode_handles(
+                    tableEntry, handles.data(), handles.size());
+                if (verbose)
+                {
+                    std::cout << "\tNumberOfCurrentValues: " << (int)count
+                              << std::endl;
+                }
+                for (size_t i = 0; i < handles.size(); i++)
+                {
+                    if (verbose)
+                    {
+                        std::cout
+                            << "\tCurrentValueStringHandleIndex[" << i
+                            << "] = " << (int)handles[i] << ", StringHandle = "
+                            << displayEnumValueByIndex(attrHandle, handles[i],
+                                                       attrTable, stringTable)
+                            << std::endl;
+                    }
+                    else
+                    {
+                        std::cout
+                            << "CurrentValue: "
+                            << displayEnumValueByIndex(attrHandle, handles[i],
+                                                       attrTable, stringTable)
+                            << std::endl;
+                    }
+                }
+                break;
+            }
+            case PLDM_BIOS_INTEGER:
+            case PLDM_BIOS_INTEGER_READ_ONLY:
+            {
+                auto cv = pldm_bios_table_attr_value_entry_integer_decode_cv(
+                    tableEntry);
+                if (verbose)
+                {
+                    std::cout << "\tCurrentValue: " << cv << std::endl;
+                }
+                else
+                {
+                    std::cout << "CurrentValue: " << cv << std::endl;
+                }
+                break;
+            }
+            case PLDM_BIOS_STRING:
+            case PLDM_BIOS_STRING_READ_ONLY:
+            {
+                variable_field currentString;
+                pldm_bios_table_attr_value_entry_string_decode_string(
+                    tableEntry, &currentString);
+                if (verbose)
+                {
+                    std::cout
+                        << "\tCurrentStringLength: " << currentString.length
+                        << std::endl
+                        << "\tCurrentString: "
+                        << std::string(
+                               reinterpret_cast<const char*>(currentString.ptr),
+                               currentString.length)
+                        << std::endl;
+                }
+                else
+                {
+                    std::cout << "CurrentValue: "
+                              << std::string(reinterpret_cast<const char*>(
+                                                 currentString.ptr),
+                                             currentString.length)
+                              << std::endl;
+                }
+
+                break;
+            }
+            case PLDM_BIOS_PASSWORD:
+            case PLDM_BIOS_PASSWORD_READ_ONLY:
+            {
+                std::cout << "Password attribute: Not Supported" << std::endl;
+                break;
+            }
+        }
+    }
+};
+
+class GetBIOSTable : public GetBIOSTableHandler
+{
+  public:
+    ~GetBIOSTable() = default;
+    GetBIOSTable() = delete;
+    GetBIOSTable(const GetBIOSTable&) = delete;
+    GetBIOSTable(GetBIOSTable&&) = default;
+    GetBIOSTable& operator=(const GetBIOSTable&) = delete;
+    GetBIOSTable& operator=(GetBIOSTable&&) = default;
+
+    using Table = std::vector<uint8_t>;
+
+    explicit GetBIOSTable(const char* type, const char* name, CLI::App* app) :
+        GetBIOSTableHandler(type, name, app)
+    {
+        app->add_option("-t,--type", pldmBIOSTableType, "pldm bios table type")
+            ->required()
+            ->transform(
+                CLI::CheckedTransformer(pldmBIOSTableTypes, CLI::ignore_case));
+    }
+
+    void exec() override
+    {
+        switch (pldmBIOSTableType)
+        {
+            case PLDM_BIOS_STRING_TABLE:
+            {
+                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+                decodeStringTable(stringTable);
+                break;
+            }
+            case PLDM_BIOS_ATTR_TABLE:
+            {
+                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+                auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+                decodeAttributeTable(attrTable, stringTable);
+                break;
+            }
+            case PLDM_BIOS_ATTR_VAL_TABLE:
+            {
+                auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+                auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+                auto attrValTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+
+                decodeAttributeValueTable(attrValTable, attrTable, stringTable);
+                break;
+            }
+        }
+    }
+
+  private:
+    pldm_bios_table_types pldmBIOSTableType;
+
+    void decodeStringTable(const std::optional<Table>& stringTable)
+    {
+        if (!stringTable)
+        {
+            std::cerr << "GetBIOSStringTable Error" << std::endl;
+            return;
+        }
+        std::cout << "PLDM StringTable: " << std::endl;
+        std::cout << "BIOSStringHandle : BIOSString" << std::endl;
+
+        for (auto tableEntry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>(
+                 stringTable->data(), stringTable->size()))
+        {
+            auto strHandle =
+                pldm_bios_table_string_entry_decode_handle(tableEntry);
+            auto strTableData = decodeStringFromStringEntry(tableEntry);
+            std::cout << strHandle << " : " << strTableData << std::endl;
+        }
+    }
+    void decodeAttributeTable(const std::optional<Table>& attrTable,
+                              const std::optional<Table>& stringTable)
+    {
+        if (!stringTable)
+        {
+            std::cerr << "GetBIOSAttributeTable Error" << std::endl;
+            return;
+        }
+        std::cout << "PLDM AttributeTable: " << std::endl;
+        for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
+                 attrTable->data(), attrTable->size()))
+        {
+            auto attrHandle =
+                pldm_bios_table_attr_entry_decode_attribute_handle(entry);
+            auto attrNameHandle =
+                pldm_bios_table_attr_entry_decode_string_handle(entry);
+            auto attrType = static_cast<pldm_bios_attribute_type>(
+                pldm_bios_table_attr_entry_decode_attribute_type(entry));
+            std::cout << "AttributeHandle: " << attrHandle
+                      << ", AttributeNameHandle: "
+                      << displayStringHandle(attrNameHandle, stringTable)
+                      << std::endl;
+            std::cout << "\tAttributeType: " << attrTypeMap.at(attrType)
+                      << std::endl;
+            switch (attrType)
+            {
+                case PLDM_BIOS_ENUMERATION:
+                case PLDM_BIOS_ENUMERATION_READ_ONLY:
+                {
+                    auto pvNum =
+                        pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+                    std::vector<uint16_t> pvHandls(pvNum);
+                    pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+                        entry, pvHandls.data(), pvHandls.size());
+                    auto defNum =
+                        pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+                    std::vector<uint8_t> defIndices(defNum);
+                    pldm_bios_table_attr_entry_enum_decode_def_indices(
+                        entry, defIndices.data(), defIndices.size());
+                    std::cout << "\tNumberOfPossibleValues: " << (int)pvNum
+                              << std::endl;
+
+                    for (size_t i = 0; i < pvHandls.size(); i++)
+                    {
+                        std::cout
+                            << "\t\tPossibleValueStringHandle"
+                            << "[" << i << "] = "
+                            << displayStringHandle(pvHandls[i], stringTable)
+                            << std::endl;
+                    }
+                    std::cout << "\tNumberOfDefaultValues: " << (int)defNum
+                              << std::endl;
+                    for (size_t i = 0; i < defIndices.size(); i++)
+                    {
+                        std::cout << "\t\tDefaultValueStringHandleIndex"
+                                  << "[" << i << "] = " << (int)defIndices[i]
+                                  << ", StringHandle = "
+                                  << displayStringHandle(
+                                         pvHandls[defIndices[i]], stringTable)
+                                  << std::endl;
+                    }
+                    break;
+                }
+                case PLDM_BIOS_INTEGER:
+                case PLDM_BIOS_INTEGER_READ_ONLY:
+                {
+                    uint64_t lower, upper, def;
+                    uint32_t scalar;
+                    pldm_bios_table_attr_entry_integer_decode(
+                        entry, &lower, &upper, &scalar, &def);
+                    std::cout << "\tLowerBound: " << lower << std::endl
+                              << "\tUpperBound: " << upper << std::endl
+                              << "\tScalarIncrement: " << scalar << std::endl
+                              << "\tDefaultValue: " << def << std::endl;
+                    break;
+                }
+                case PLDM_BIOS_STRING:
+                case PLDM_BIOS_STRING_READ_ONLY:
+                {
+                    auto strType =
+                        pldm_bios_table_attr_entry_string_decode_string_type(
+                            entry);
+                    auto min =
+                        pldm_bios_table_attr_entry_string_decode_min_length(
+                            entry);
+                    auto max =
+                        pldm_bios_table_attr_entry_string_decode_max_length(
+                            entry);
+                    auto def =
+                        pldm_bios_table_attr_entry_string_decode_def_string_length(
+                            entry);
+                    std::vector<char> defString(def + 1);
+                    pldm_bios_table_attr_entry_string_decode_def_string(
+                        entry, defString.data(), defString.size());
+                    std::cout
+                        << "\tStringType: 0x" << std::hex << std::setw(2)
+                        << std::setfill('0') << (int)strType << std::dec
+                        << std::setw(0) << std::endl
+                        << "\tMinimumStringLength: " << (int)min << std::endl
+                        << "\tMaximumStringLength: " << (int)max << std::endl
+                        << "\tDefaultStringLength: " << (int)def << std::endl
+                        << "\tDefaultString: " << defString.data() << std::endl;
+                    break;
+                }
+                case PLDM_BIOS_PASSWORD:
+                case PLDM_BIOS_PASSWORD_READ_ONLY:
+                    std::cout << "Password attribute: Not Supported"
+                              << std::endl;
+            }
+        }
+    }
+    void decodeAttributeValueTable(const std::optional<Table>& attrValTable,
+                                   const std::optional<Table>& attrTable,
+                                   const std::optional<Table>& stringTable)
+    {
+        if (!attrValTable)
+        {
+            std::cerr << "GetBIOSAttributeValueTable Error" << std::endl;
+            return;
+        }
+        std::cout << "PLDM AttributeValueTable: " << std::endl;
+        for (auto tableEntry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+                 attrValTable->data(), attrValTable->size()))
+        {
+            displayAttributeValueEntry(tableEntry, attrTable, stringTable,
+                                       true);
+        }
+    }
+};
+
+class GetBIOSAttributeCurrentValueByHandle : public GetBIOSTableHandler
+{
+  public:
+    ~GetBIOSAttributeCurrentValueByHandle() = default;
+    GetBIOSAttributeCurrentValueByHandle(
+        const GetBIOSAttributeCurrentValueByHandle&) = delete;
+    GetBIOSAttributeCurrentValueByHandle(
+        GetBIOSAttributeCurrentValueByHandle&&) = delete;
+    GetBIOSAttributeCurrentValueByHandle&
+        operator=(const GetBIOSAttributeCurrentValueByHandle&) = delete;
+    GetBIOSAttributeCurrentValueByHandle&
+        operator=(GetBIOSAttributeCurrentValueByHandle&&) = delete;
+
+    explicit GetBIOSAttributeCurrentValueByHandle(const char* type,
+                                                  const char* name,
+                                                  CLI::App* app) :
+        GetBIOSTableHandler(type, name, app)
+    {
+        app->add_option("-a, --attribute", attrName, "pldm bios attribute name")
+            ->required();
+    }
+
+    void exec()
+    {
+        auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+        auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+        if (!stringTable || !attrTable)
+        {
+            std::cout << "StringTable/AttrTable Unavaliable" << std::endl;
+            return;
+        }
+
+        auto handle = findAttrHandleByName(attrName, *attrTable, *stringTable);
+        if (!handle)
+        {
+
+            std::cerr << "Can not find the attribute " << attrName << std::endl;
+            return;
+        }
+
+        std::vector<uint8_t> requestMsg(
+            sizeof(pldm_msg_hdr) +
+            PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_bios_attribute_current_value_by_handle_req(
+            instanceId, 0, PLDM_GET_FIRSTPART, *handle, request);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
+            return;
+        }
+
+        std::vector<uint8_t> responseMsg;
+        rc = pldmSendRecv(requestMsg, responseMsg);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
+            return;
+        }
+
+        uint8_t cc = 0, transferFlag = 0;
+        uint32_t nextTransferHandle = 0;
+        struct variable_field attributeData;
+        auto responsePtr =
+            reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+        auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
+
+        rc = decode_get_bios_attribute_current_value_by_handle_resp(
+            responsePtr, payloadLength, &cc, &nextTransferHandle, &transferFlag,
+            &attributeData);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+            return;
+        }
+
+        auto tableEntry =
+            reinterpret_cast<const struct pldm_bios_attr_val_table_entry*>(
+                attributeData.ptr);
+
+        displayAttributeValueEntry(tableEntry, attrTable, stringTable, false);
+    }
+
+  private:
+    std::string attrName;
+};
+
+class SetBIOSAttributeCurrentValue : public GetBIOSTableHandler
+{
+  public:
+    ~SetBIOSAttributeCurrentValue() = default;
+    SetBIOSAttributeCurrentValue() = delete;
+    SetBIOSAttributeCurrentValue(const SetBIOSAttributeCurrentValue&) = delete;
+    SetBIOSAttributeCurrentValue(SetBIOSAttributeCurrentValue&&) = default;
+    SetBIOSAttributeCurrentValue&
+        operator=(const SetBIOSAttributeCurrentValue&) = delete;
+    SetBIOSAttributeCurrentValue&
+        operator=(SetBIOSAttributeCurrentValue&&) = default;
+
+    explicit SetBIOSAttributeCurrentValue(const char* type, const char* name,
+                                          CLI::App* app) :
+        GetBIOSTableHandler(type, name, app)
+    {
+        app->add_option("-a, --attribute", attrName, "pldm attribute name")
+            ->required();
+        app->add_option("-d, --data", attrValue, "pldm attribute value")
+            ->required();
+        // -v is conflict with --verbose in class CommandInterface, so used -d
+    }
+
+    void exec()
+    {
+        auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+        auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+        auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+
+        if (!stringTable || !attrTable)
+        {
+            std::cout << "StringTable/AttrTable Unavaliable" << std::endl;
+            return;
+        }
+
+        auto attrEntry =
+            findAttrEntryByName(attrName, *attrTable, *stringTable);
+        if (attrEntry == nullptr)
+        {
+            std::cout << "Could not find attribute :" << attrName << std::endl;
+            return;
+        }
+
+        std::vector<uint8_t> requestMsg;
+
+        int rc = 0;
+        auto attrType = attrEntry->attr_type;
+        size_t entryLength = 1;
+        std::vector<uint8_t> attrValueEntry(entryLength, 0);
+
+        switch (attrType)
+        {
+            case PLDM_BIOS_ENUMERATION_READ_ONLY:
+            case PLDM_BIOS_STRING_READ_ONLY:
+            case PLDM_BIOS_INTEGER_READ_ONLY:
+            {
+                std::cerr << "Set  attribute error: " << attrName
+                          << "is read only." << std::endl;
+                return;
+            }
+            case PLDM_BIOS_ENUMERATION:
+            {
+                entryLength =
+                    pldm_bios_table_attr_value_entry_encode_enum_length(1);
+                auto pvNum =
+                    pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
+                std::vector<uint16_t> pvHdls(pvNum, 0);
+                pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+                    attrEntry, pvHdls.data(), pvNum);
+                auto stringEntry = pldm_bios_table_string_find_by_string(
+                    stringTable->data(), stringTable->size(),
+                    attrValue.c_str());
+                if (stringEntry == nullptr)
+                {
+                    std::cout
+                        << "Set Attribute Error: It's not a possible value"
+                        << std::endl;
+                    return;
+                }
+                auto valueHandle =
+                    pldm_bios_table_string_entry_decode_handle(stringEntry);
+
+                uint8_t i;
+                for (i = 0; i < pvNum; i++)
+                {
+                    if (valueHandle == pvHdls[i])
+                        break;
+                }
+                if (i == pvNum)
+                {
+                    std::cout
+                        << "Set Attribute Error: It's not a possible value"
+                        << std::endl;
+                    return;
+                }
+
+                attrValueEntry.resize(entryLength);
+                std::vector<uint8_t> handles = {i};
+                pldm_bios_table_attr_value_entry_encode_enum(
+                    attrValueEntry.data(), attrValueEntry.size(),
+                    attrEntry->attr_handle, attrType, 1, handles.data());
+                break;
+            }
+            case PLDM_BIOS_STRING:
+            {
+                entryLength =
+                    pldm_bios_table_attr_value_entry_encode_string_length(
+                        attrValue.size());
+
+                attrValueEntry.resize(entryLength);
+
+                pldm_bios_table_attr_value_entry_encode_string(
+                    attrValueEntry.data(), entryLength, attrEntry->attr_handle,
+                    attrType, attrValue.size(), attrValue.c_str());
+                break;
+            }
+            case PLDM_BIOS_INTEGER:
+            {
+                uint64_t value = std::stoll(attrValue);
+                entryLength =
+                    pldm_bios_table_attr_value_entry_encode_integer_length();
+                attrValueEntry.resize(entryLength);
+                pldm_bios_table_attr_value_entry_encode_integer(
+                    attrValueEntry.data(), entryLength, attrEntry->attr_handle,
+                    attrType, value);
+                break;
+            }
+        }
+
+        requestMsg.resize(entryLength + sizeof(pldm_msg_hdr) +
+                          PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES);
+
+        rc = encode_set_bios_attribute_current_value_req(
+            instanceId, 0, PLDM_START_AND_END, attrValueEntry.data(),
+            attrValueEntry.size(),
+            reinterpret_cast<pldm_msg*>(requestMsg.data()),
+            requestMsg.size() - sizeof(pldm_msg_hdr));
+
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
+            return;
+        }
+        std::vector<uint8_t> responseMsg;
+        rc = pldmSendRecv(requestMsg, responseMsg);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
+            return;
+        }
+        uint8_t cc = 0;
+        uint32_t nextTransferHandle = 0;
+        auto responsePtr =
+            reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+        auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
+
+        rc = decode_set_bios_attribute_current_value_resp(
+            responsePtr, payloadLength, &cc, &nextTransferHandle);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+            return;
+        }
+
+        std::cout << "SetBIOSAttributeCurrentValue: SUCCESS" << std::endl;
+    }
+
+  private:
+    std::string attrName;
+    std::string attrValue;
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto bios = app.add_subcommand("bios", "bios type command");
+    bios->require_subcommand(1);
+    auto getDateTime = bios->add_subcommand("GetDateTime", "get date time");
+    commands.push_back(
+        std::make_unique<GetDateTime>("bios", "GetDateTime", getDateTime));
+
+    auto setDateTime =
+        bios->add_subcommand("SetDateTime", "set host date time");
+    commands.push_back(
+        std::make_unique<SetDateTime>("bios", "setDateTime", setDateTime));
+
+    auto getBIOSTable = bios->add_subcommand("GetBIOSTable", "get bios table");
+    commands.push_back(
+        std::make_unique<GetBIOSTable>("bios", "GetBIOSTable", getBIOSTable));
+
+    auto getBIOSAttributeCurrentValueByHandle =
+        bios->add_subcommand("GetBIOSAttributeCurrentValueByHandle",
+                             "get bios attribute current value by handle");
+    commands.push_back(std::make_unique<GetBIOSAttributeCurrentValueByHandle>(
+        "bios", "GetBIOSAttributeCurrentValueByHandle",
+        getBIOSAttributeCurrentValueByHandle));
+
+    auto setBIOSAttributeCurrentValue = bios->add_subcommand(
+        "SetBIOSAttributeCurrentValue", "set bios attribute current value");
+    commands.push_back(std::make_unique<SetBIOSAttributeCurrentValue>(
+        "bios", "SetBIOSAttributeCurrentValue", setBIOSAttributeCurrentValue));
+}
+
+} // namespace bios
+
+} // namespace pldmtool
diff --git a/pldmtool/pldm_bios_cmd.hpp b/pldmtool/pldm_bios_cmd.hpp
new file mode 100644
index 0000000..cb80b0f
--- /dev/null
+++ b/pldmtool/pldm_bios_cmd.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include <CLI/CLI.hpp>
+
+namespace pldmtool
+{
+
+namespace bios
+{
+
+void registerCommand(CLI::App& app);
+
+} // namespace bios
+
+} // namespace pldmtool
diff --git a/pldmtool/pldm_cmd_helper.cpp b/pldmtool/pldm_cmd_helper.cpp
new file mode 100644
index 0000000..7002c79
--- /dev/null
+++ b/pldmtool/pldm_cmd_helper.cpp
@@ -0,0 +1,247 @@
+#include "pldm_cmd_helper.hpp"
+
+#include "libpldm/requester/pldm.h"
+
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <systemd/sd-bus.h>
+
+#include <sdbusplus/server.hpp>
+#include <xyz/openbmc_project/Logging/Entry/server.hpp>
+
+#include <exception>
+
+namespace pldmtool
+{
+
+namespace helper
+{
+/*
+ * print the input buffer if pldm verbosity is enabled.
+ *
+ */
+void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose)
+{
+    if (pldmVerbose && !buffer.empty())
+    {
+        std::ostringstream tempStream;
+        for (int byte : buffer)
+        {
+            tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
+                       << " ";
+        }
+        std::cout << tempStream.str() << std::endl;
+    }
+}
+/*
+ * Initialize the socket, send pldm command & recieve response from socket
+ *
+ */
+int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg,
+                     std::vector<uint8_t>& responseMsg, bool pldmVerbose)
+{
+
+    const char devPath[] = "\0mctp-mux";
+    int returnCode = 0;
+
+    int sockFd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+    if (-1 == sockFd)
+    {
+        returnCode = -errno;
+        std::cerr << "Failed to create the socket : RC = " << sockFd << "\n";
+        return returnCode;
+    }
+    Logger(pldmVerbose, "Success in creating the socket : RC = ", sockFd);
+
+    struct sockaddr_un addr
+    {};
+    addr.sun_family = AF_UNIX;
+
+    memcpy(addr.sun_path, devPath, sizeof(devPath) - 1);
+
+    CustomFD socketFd(sockFd);
+    int result = connect(socketFd(), reinterpret_cast<struct sockaddr*>(&addr),
+                         sizeof(devPath) + sizeof(addr.sun_family) - 1);
+    if (-1 == result)
+    {
+        returnCode = -errno;
+        std::cerr << "Failed to connect to socket : RC = " << returnCode
+                  << "\n";
+        return returnCode;
+    }
+    Logger(pldmVerbose, "Success in connecting to socket : RC = ", returnCode);
+
+    auto pldmType = MCTP_MSG_TYPE_PLDM;
+    result = write(socketFd(), &pldmType, sizeof(pldmType));
+    if (-1 == result)
+    {
+        returnCode = -errno;
+        std::cerr << "Failed to send message type as pldm to mctp : RC = "
+                  << returnCode << "\n";
+        return returnCode;
+    }
+    Logger(
+        pldmVerbose,
+        "Success in sending message type as pldm to mctp : RC = ", returnCode);
+
+    result = send(socketFd(), requestMsg.data(), requestMsg.size(), 0);
+    if (-1 == result)
+    {
+        returnCode = -errno;
+        std::cerr << "Write to socket failure : RC = " << returnCode << "\n";
+        return returnCode;
+    }
+    Logger(pldmVerbose, "Write to socket successful : RC = ", result);
+
+    // Read the response from socket
+    ssize_t peekedLength = recv(socketFd(), nullptr, 0, MSG_TRUNC | MSG_PEEK);
+    if (0 == peekedLength)
+    {
+        std::cerr << "Socket is closed : peekedLength = " << peekedLength
+                  << "\n";
+        return returnCode;
+    }
+    else if (peekedLength <= -1)
+    {
+        returnCode = -errno;
+        std::cerr << "recv() system call failed : RC = " << returnCode << "\n";
+        return returnCode;
+    }
+    else
+    {
+        auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&requestMsg[2]);
+        do
+        {
+            ssize_t peekedLength =
+                recv(socketFd(), nullptr, 0, MSG_PEEK | MSG_TRUNC);
+            responseMsg.resize(peekedLength);
+            auto recvDataLength =
+                recv(socketFd(), reinterpret_cast<void*>(responseMsg.data()),
+                     peekedLength, 0);
+            auto resphdr =
+                reinterpret_cast<const pldm_msg_hdr*>(&responseMsg[2]);
+            if (recvDataLength == peekedLength &&
+                resphdr->instance_id == reqhdr->instance_id &&
+                resphdr->request != PLDM_REQUEST)
+            {
+                Logger(pldmVerbose, "Total length:", recvDataLength);
+                break;
+            }
+            else if (recvDataLength != peekedLength)
+            {
+                std::cerr << "Failure to read response length packet: length = "
+                          << recvDataLength << "\n";
+                return returnCode;
+            }
+        } while (1);
+    }
+
+    returnCode = shutdown(socketFd(), SHUT_RDWR);
+    if (-1 == returnCode)
+    {
+        returnCode = -errno;
+        std::cerr << "Failed to shutdown the socket : RC = " << returnCode
+                  << "\n";
+        return returnCode;
+    }
+
+    Logger(pldmVerbose, "Shutdown Socket successful :  RC = ", returnCode);
+    return PLDM_SUCCESS;
+}
+
+void CommandInterface::exec()
+{
+    static constexpr auto pldmObjPath = "/xyz/openbmc_project/pldm";
+    static constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
+    auto& bus = pldm::utils::DBusHandler::getBus();
+    try
+    {
+        auto service =
+            pldm::utils::DBusHandler().getService(pldmObjPath, pldmRequester);
+        auto method = bus.new_method_call(service.c_str(), pldmObjPath,
+                                          pldmRequester, "GetInstanceId");
+        method.append(mctp_eid);
+        auto reply = bus.call(method);
+        reply.read(instanceId);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "GetInstanceId D-Bus call failed, MCTP id = " << mctp_eid
+                  << ", error = " << e.what() << "\n";
+        return;
+    }
+    auto [rc, requestMsg] = createRequestMsg();
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Failed to encode request message for " << pldmType << ":"
+                  << commandName << " rc = " << rc << "\n";
+        return;
+    }
+
+    std::vector<uint8_t> responseMsg;
+    rc = pldmSendRecv(requestMsg, responseMsg);
+
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n";
+        return;
+    }
+
+    auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr));
+}
+
+int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg,
+                                   std::vector<uint8_t>& responseMsg)
+{
+
+    // Insert the PLDM message type and EID at the beginning of the
+    // msg.
+    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
+    requestMsg.insert(requestMsg.begin(), mctp_eid);
+
+    bool mctpVerbose = pldmVerbose;
+
+    // By default enable request/response msgs for pldmtool raw commands.
+    if (CommandInterface::pldmType == "raw")
+    {
+        pldmVerbose = true;
+    }
+
+    Logger(pldmVerbose, "Request Message:", "");
+    printBuffer(requestMsg, pldmVerbose);
+
+    if (mctp_eid != PLDM_ENTITY_ID)
+    {
+        int fd = pldm_open();
+        if (-1 == fd)
+        {
+            std::cerr << "failed to init mctp "
+                      << "\n";
+            return -1;
+        }
+        uint8_t* responseMessage = nullptr;
+        size_t responseMessageSize{};
+        pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2,
+                       requestMsg.size() - 2, &responseMessage,
+                       &responseMessageSize);
+
+        Logger(pldmVerbose, "Response Message:", "");
+        responseMsg.resize(responseMessageSize);
+        memcpy(responseMsg.data(), responseMessage, responseMsg.size());
+
+        free(responseMessage);
+        printBuffer(responseMsg, pldmVerbose);
+    }
+    else
+    {
+        mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose);
+        Logger(pldmVerbose, "Response Message:", "");
+        printBuffer(responseMsg, pldmVerbose);
+        responseMsg.erase(responseMsg.begin(),
+                          responseMsg.begin() + 2 /* skip the mctp header */);
+    }
+    return PLDM_SUCCESS;
+}
+} // namespace helper
+} // namespace pldmtool
diff --git a/pldmtool/pldm_cmd_helper.hpp b/pldmtool/pldm_cmd_helper.hpp
new file mode 100644
index 0000000..7e7f03a
--- /dev/null
+++ b/pldmtool/pldm_cmd_helper.hpp
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "libpldm/base.h"
+#include "libpldm/bios.h"
+#include "libpldm/fru.h"
+#include "libpldm/platform.h"
+
+#include "common/utils.hpp"
+
+#include <err.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <CLI/CLI.hpp>
+
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <utility>
+
+namespace pldmtool
+{
+
+namespace helper
+{
+
+using namespace pldm::utils;
+constexpr uint8_t PLDM_ENTITY_ID = 8;
+constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
+
+/** @brief Print the buffer
+ *
+ *  @param[in]  buffer  - Buffer to print
+ *  @param[in]  pldmVerbose -verbosity flag - true/false
+ *
+ *  @return - None
+ */
+void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose);
+
+/** @brief print the input message if pldmverbose is enabled
+ *
+ *  @param[in]  pldmVerbose - verbosity flag - true/false
+ *  @param[in]  msg         - message to print
+ *  @param[in]  data        - data to print
+ *
+ *  @return - None
+ */
+
+template <class T>
+void Logger(bool pldmverbose, const char* msg, const T& data)
+{
+    if (pldmverbose)
+    {
+        std::stringstream s;
+        s << data;
+        std::cout << msg << s.str() << std::endl;
+    }
+}
+/** @brief MCTP socket read/recieve
+ *
+ *  @param[in]  requestMsg - Request message to compare against loopback
+ *              message recieved from mctp socket
+ *  @param[out] responseMsg - Response buffer recieved from mctp socket
+ *  @param[in]  pldmVerbose - verbosity flag - true/false
+ *
+ *  @return -   0 on success.
+ *             -1 or -errno on failure.
+ */
+int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg,
+                     std::vector<uint8_t>& responseMsg, bool pldmVerbose);
+
+class CommandInterface
+{
+
+  public:
+    explicit CommandInterface(const char* type, const char* name,
+                              CLI::App* app) :
+        pldmType(type),
+        commandName(name), mctp_eid(PLDM_ENTITY_ID), instanceId(0)
+    {
+        app->add_option("-m,--mctp_eid", mctp_eid, "MCTP endpoint ID");
+        app->add_flag("-v, --verbose", pldmVerbose);
+        app->callback([&]() { exec(); });
+    }
+
+    virtual ~CommandInterface() = default;
+
+    virtual std::pair<int, std::vector<uint8_t>> createRequestMsg() = 0;
+
+    virtual void parseResponseMsg(struct pldm_msg* responsePtr,
+                                  size_t payloadLength) = 0;
+
+    virtual void exec();
+
+    int pldmSendRecv(std::vector<uint8_t>& requestMsg,
+                     std::vector<uint8_t>& responseMsg);
+
+  private:
+    const std::string pldmType;
+    const std::string commandName;
+    uint8_t mctp_eid;
+    bool pldmVerbose;
+
+  protected:
+    uint8_t instanceId;
+};
+
+} // namespace helper
+} // namespace pldmtool
diff --git a/pldmtool/pldm_fru_cmd.cpp b/pldmtool/pldm_fru_cmd.cpp
new file mode 100644
index 0000000..2075a48
--- /dev/null
+++ b/pldmtool/pldm_fru_cmd.cpp
@@ -0,0 +1,89 @@
+#include "pldm_fru_cmd.hpp"
+
+#include "pldm_cmd_helper.hpp"
+
+namespace pldmtool
+{
+
+namespace fru
+{
+
+namespace
+{
+
+using namespace pldmtool::helper;
+
+std::vector<std::unique_ptr<CommandInterface>> commands;
+
+} // namespace
+
+class GetFruRecordTableMetadata : public CommandInterface
+{
+  public:
+    ~GetFruRecordTableMetadata() = default;
+    GetFruRecordTableMetadata() = delete;
+    GetFruRecordTableMetadata(const GetFruRecordTableMetadata&) = delete;
+    GetFruRecordTableMetadata(GetFruRecordTableMetadata&&) = default;
+    GetFruRecordTableMetadata&
+        operator=(const GetFruRecordTableMetadata&) = delete;
+    GetFruRecordTableMetadata& operator=(GetFruRecordTableMetadata&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_fru_record_table_metadata_req(
+            instanceId, request, PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0;
+        uint8_t fru_data_major_version, fru_data_minor_version;
+        uint32_t fru_table_maximum_size, fru_table_length;
+        uint16_t total_record_set_identifiers, total_table_records;
+        uint32_t checksum;
+
+        auto rc = decode_get_fru_record_table_metadata_resp(
+            responsePtr, payloadLength, &cc, &fru_data_major_version,
+            &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+            &total_record_set_identifiers, &total_table_records, &checksum);
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+            return;
+        }
+        std::cout << "FRUDATAMajorVersion : "
+                  << static_cast<uint32_t>(fru_data_major_version) << std::endl;
+        std::cout << "FRUDATAMinorVersion : "
+                  << static_cast<uint32_t>(fru_data_minor_version) << std::endl;
+        std::cout << "FRUTableMaximumSize : " << fru_table_maximum_size
+                  << std::endl;
+        std::cout << "FRUTableLength : " << fru_table_length << std::endl;
+        std::cout << "Total number of Record Set Identifiers in table : "
+                  << total_record_set_identifiers << std::endl;
+        std::cout << "Total number of records in table :  "
+                  << total_table_records << std::endl;
+        std::cout << "FRU DATAStructureTableIntegrityChecksum :  " << checksum
+                  << std::endl;
+    }
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto fru = app.add_subcommand("fru", "FRU type command");
+    fru->require_subcommand(1);
+    auto getFruRecordTableMetadata = fru->add_subcommand(
+        "GetFruRecordTableMetadata", "get FRU record table metadata");
+    commands.push_back(std::make_unique<GetFruRecordTableMetadata>(
+        "fru", "GetFruRecordTableMetadata", getFruRecordTableMetadata));
+}
+
+} // namespace fru
+
+} // namespace pldmtool
diff --git a/pldmtool/pldm_fru_cmd.hpp b/pldmtool/pldm_fru_cmd.hpp
new file mode 100644
index 0000000..1cb3210
--- /dev/null
+++ b/pldmtool/pldm_fru_cmd.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <CLI/CLI.hpp>
+
+namespace pldmtool
+{
+
+namespace fru
+{
+
+void registerCommand(CLI::App& app);
+}
+
+} // namespace pldmtool
diff --git a/pldmtool/pldm_platform_cmd.cpp b/pldmtool/pldm_platform_cmd.cpp
new file mode 100644
index 0000000..2c62f42
--- /dev/null
+++ b/pldmtool/pldm_platform_cmd.cpp
@@ -0,0 +1,647 @@
+#include "pldm_cmd_helper.hpp"
+
+namespace pldmtool
+{
+
+namespace platform
+{
+
+namespace
+{
+
+using namespace pldmtool::helper;
+std::vector<std::unique_ptr<CommandInterface>> commands;
+
+} // namespace
+
+class GetPDR : public CommandInterface
+{
+  public:
+    ~GetPDR() = default;
+    GetPDR() = delete;
+    GetPDR(const GetPDR&) = delete;
+    GetPDR(GetPDR&&) = default;
+    GetPDR& operator=(const GetPDR&) = delete;
+    GetPDR& operator=(GetPDR&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    // The maximum number of record bytes requested to be returned in the
+    // response to this instance of the GetPDR command.
+    static constexpr uint16_t requestCount = 128;
+
+    explicit GetPDR(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option(
+               "-d,--data", recordHandle,
+               "retrieve individual PDRs from a PDR Repository\n"
+               "eg: The recordHandle value for the PDR to be retrieved and 0 "
+               "means get first PDR in the repository.")
+            ->required();
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_PDR_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_pdr_req(instanceId, recordHandle, 0,
+                                     PLDM_GET_FIRSTPART, requestCount, 0,
+                                     request, PLDM_GET_PDR_REQ_BYTES);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t completionCode = 0;
+        uint8_t recordData[65535] = {0};
+        uint32_t nextRecordHndl = 0;
+        uint32_t nextDataTransferHndl = 0;
+        uint8_t transferFlag = 0;
+        uint16_t respCnt = 0;
+        uint8_t transferCRC = 0;
+
+        auto rc = decode_get_pdr_resp(
+            responsePtr, payloadLength, &completionCode, &nextRecordHndl,
+            &nextDataTransferHndl, &transferFlag, &respCnt, recordData,
+            sizeof(recordData), &transferCRC);
+
+        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)completionCode
+                      << std::endl;
+            return;
+        }
+
+        printPDRMsg(nextRecordHndl, respCnt, recordData);
+    }
+
+  private:
+    const std::map<uint16_t, std::string> entityType = {
+        {64, "System Board"},
+        {66, "Memory Module"},
+        {67, "Processor Module"},
+        {137, "Management Controller"},
+        {69, "Chassis front panel board (control panel)"},
+        {123, "Power converter"},
+        {45, "System chassis (main enclosure)"},
+        {11521, "System (logical)"},
+    };
+
+    std::string getEntityName(uint16_t type)
+    {
+        try
+        {
+            return entityType.at(type);
+        }
+        catch (const std::out_of_range& e)
+        {
+            return std::to_string(static_cast<unsigned>(type)) + "(OEM)";
+        }
+    }
+
+    void printPDRFruRecordSet(uint8_t* data)
+    {
+        if (data == NULL)
+        {
+            return;
+        }
+
+        data += sizeof(pldm_pdr_hdr);
+        pldm_pdr_fru_record_set* pdr =
+            reinterpret_cast<pldm_pdr_fru_record_set*>(data);
+
+        std::cout << "PLDMTerminusHandle: " << pdr->terminus_handle
+                  << std::endl;
+        std::cout << "FRURecordSetIdentifier: " << pdr->fru_rsi << std::endl;
+        std::cout << "entityType: " << getEntityName(pdr->entity_type)
+                  << std::endl;
+        std::cout << "entityInstanceNumber: " << pdr->entity_instance_num
+                  << std::endl;
+        std::cout << "containerID: " << pdr->container_id << std::endl;
+    }
+
+    void printPDREntityAssociation(uint8_t* data)
+    {
+        const std::map<uint8_t, const char*> assocationType = {
+            {PLDM_ENTITY_ASSOCIAION_PHYSICAL, "Physical"},
+            {PLDM_ENTITY_ASSOCIAION_LOGICAL, "Logical"},
+        };
+
+        if (data == NULL)
+        {
+            return;
+        }
+
+        data += sizeof(pldm_pdr_hdr);
+        pldm_pdr_entity_association* pdr =
+            reinterpret_cast<pldm_pdr_entity_association*>(data);
+
+        std::cout << "containerID: " << pdr->container_id << std::endl;
+        std::cout << "associationType: "
+                  << assocationType.at(pdr->association_type) << std::endl
+                  << std::endl;
+
+        std::cout << "containerEntityType: "
+                  << getEntityName(pdr->container.entity_type) << std::endl;
+        std::cout << "containerEntityInstanceNumber: "
+                  << pdr->container.entity_instance_num << std::endl;
+        std::cout << "containerEntityContainerID: "
+                  << pdr->container.entity_container_id << std::endl;
+
+        std::cout << "containedEntityCount: "
+                  << static_cast<unsigned>(pdr->num_children) << std::endl
+                  << std::endl;
+
+        auto child = reinterpret_cast<pldm_entity*>(&pdr->children[0]);
+        for (int i = 0; i < pdr->num_children; ++i)
+        {
+            std::cout << "containedEntityType[" << i + 1
+                      << "]: " << getEntityName(child->entity_type)
+                      << std::endl;
+            std::cout << "containedEntityInstanceNumber[" << i + 1
+                      << "]: " << child->entity_instance_num << std::endl;
+            std::cout << "containedEntityContainerID[" << i + 1
+                      << "]: " << child->entity_container_id << std::endl
+                      << std::endl;
+            ++child;
+        }
+    }
+
+    void printEffecterHdrPDR(pldm_pdr_hdr* hdr)
+    {
+        std::cout << "recordHandle: " << hdr->record_handle << std::endl;
+        std::cout << "PDRHeaderVersion: " << unsigned(hdr->version)
+                  << std::endl;
+        std::cout << "PDRType: " << unsigned(hdr->type) << std::endl;
+        std::cout << "recordChangeNumber: " << hdr->record_change_num
+                  << std::endl;
+        std::cout << "dataLength: " << hdr->length << std::endl;
+    }
+
+    void printNumericEffecterPDR(uint8_t* data)
+    {
+        struct pldm_numeric_effecter_value_pdr* pdr =
+            (struct pldm_numeric_effecter_value_pdr*)data;
+        printEffecterHdrPDR(&pdr->hdr);
+        std::cout << "PLDMTerminusHandle: " << pdr->terminus_handle
+                  << std::endl;
+        std::cout << "effecterID: " << pdr->effecter_id << std::endl;
+        std::cout << "entityType: " << pdr->entity_type << std::endl;
+        std::cout << "entityInstanceNumber: " << pdr->entity_instance
+                  << std::endl;
+        std::cout << "containerID: " << pdr->container_id << std::endl;
+        std::cout << "effecterSemanticID: " << pdr->effecter_semantic_id
+                  << std::endl;
+        std::cout << "effecterInit: " << unsigned(pdr->effecter_init)
+                  << std::endl;
+        std::cout << "effecterAuxiliaryNames: "
+                  << (unsigned(pdr->effecter_auxiliary_names) ? "true"
+                                                              : "false")
+                  << std::endl;
+        std::cout << "baseUnit: " << unsigned(pdr->base_unit) << std::endl;
+        std::cout << "unitModifier: " << unsigned(pdr->unit_modifier)
+                  << std::endl;
+        std::cout << "rateUnit: " << unsigned(pdr->rate_unit) << std::endl;
+        std::cout << "baseOEMUnitHandle: "
+                  << unsigned(pdr->base_oem_unit_handle) << std::endl;
+        std::cout << "auxUnit: " << unsigned(pdr->aux_unit) << std::endl;
+        std::cout << "auxUnitModifier: " << unsigned(pdr->aux_unit_modifier)
+                  << std::endl;
+        std::cout << "auxrateUnit: " << unsigned(pdr->aux_rate_unit)
+                  << std::endl;
+        std::cout << "auxOEMUnitHandle: " << unsigned(pdr->aux_oem_unit_handle)
+                  << std::endl;
+        std::cout << "isLinear: "
+                  << (unsigned(pdr->is_linear) ? "true" : "false") << std::endl;
+        std::cout << "effecterDataSize: " << unsigned(pdr->effecter_data_size)
+                  << std::endl;
+        std::cout << "resolution: " << pdr->resolution << std::endl;
+        std::cout << "offset: " << pdr->offset << std::endl;
+        std::cout << "accuracy: " << pdr->accuracy << std::endl;
+        std::cout << "plusTolerance: " << unsigned(pdr->plus_tolerance)
+                  << std::endl;
+        std::cout << "minusTolerance: " << unsigned(pdr->minus_tolerance)
+                  << std::endl;
+        std::cout << "stateTransitionInterval: "
+                  << pdr->state_transition_interval << std::endl;
+        std::cout << "TransitionInterval: " << pdr->transition_interval
+                  << std::endl;
+        switch (pdr->effecter_data_size)
+        {
+            case PLDM_EFFECTER_DATA_SIZE_UINT8:
+                std::cout << "maxSettable: "
+                          << unsigned(pdr->max_set_table.value_u8) << std::endl;
+                std::cout << "minSettable: "
+                          << unsigned(pdr->min_set_table.value_u8) << std::endl;
+                break;
+            case PLDM_EFFECTER_DATA_SIZE_SINT8:
+                std::cout << "maxSettable: "
+                          << unsigned(pdr->max_set_table.value_s8) << std::endl;
+                std::cout << "minSettable: "
+                          << unsigned(pdr->min_set_table.value_s8) << std::endl;
+                break;
+            case PLDM_EFFECTER_DATA_SIZE_UINT16:
+                std::cout << "maxSettable: " << pdr->max_set_table.value_u16
+                          << std::endl;
+                std::cout << "minSettable: " << pdr->min_set_table.value_u16
+                          << std::endl;
+                break;
+            case PLDM_EFFECTER_DATA_SIZE_SINT16:
+                std::cout << "maxSettable: " << pdr->max_set_table.value_s16
+                          << std::endl;
+                std::cout << "minSettable: " << pdr->min_set_table.value_s16
+                          << std::endl;
+                break;
+            case PLDM_EFFECTER_DATA_SIZE_UINT32:
+                std::cout << "maxSettable: " << pdr->max_set_table.value_u32
+                          << std::endl;
+                std::cout << "minSettable: " << pdr->min_set_table.value_u32
+                          << std::endl;
+                break;
+            case PLDM_EFFECTER_DATA_SIZE_SINT32:
+                std::cout << "maxSettable: " << pdr->max_set_table.value_s32
+                          << std::endl;
+                std::cout << "minSettable: " << pdr->min_set_table.value_s32
+                          << std::endl;
+                break;
+            default:
+                break;
+        }
+        std::cout << "rangeFieldFormat: " << unsigned(pdr->range_field_format)
+                  << std::endl;
+        std::cout << "rangeFieldSupport: "
+                  << unsigned(pdr->range_field_support.byte) << std::endl;
+        switch (pdr->range_field_format)
+        {
+            case PLDM_RANGE_FIELD_FORMAT_UINT8:
+                std::cout << "nominalValue: "
+                          << unsigned(pdr->nominal_value.value_u8) << std::endl;
+                std::cout << "normalMax: " << unsigned(pdr->normal_max.value_u8)
+                          << std::endl;
+                std::cout << "normalMin: " << unsigned(pdr->normal_min.value_u8)
+                          << std::endl;
+                std::cout << "ratedMax: " << unsigned(pdr->rated_max.value_u8)
+                          << std::endl;
+                std::cout << "ratedMin: " << unsigned(pdr->rated_min.value_u8)
+                          << std::endl;
+                break;
+            case PLDM_RANGE_FIELD_FORMAT_SINT8:
+                std::cout << "nominalValue: "
+                          << unsigned(pdr->nominal_value.value_s8) << std::endl;
+                std::cout << "normalMax: " << unsigned(pdr->normal_max.value_s8)
+                          << std::endl;
+                std::cout << "normalMin: " << unsigned(pdr->normal_min.value_s8)
+                          << std::endl;
+                std::cout << "ratedMax: " << unsigned(pdr->rated_max.value_s8)
+                          << std::endl;
+                std::cout << "ratedMin: " << unsigned(pdr->rated_min.value_s8)
+                          << std::endl;
+                break;
+            case PLDM_RANGE_FIELD_FORMAT_UINT16:
+                std::cout << "nominalValue: " << pdr->nominal_value.value_u16
+                          << std::endl;
+                std::cout << "normalMax: " << pdr->normal_max.value_u16
+                          << std::endl;
+                std::cout << "normalMin: " << pdr->normal_min.value_u16
+                          << std::endl;
+                std::cout << "ratedMax: " << pdr->rated_max.value_u16
+                          << std::endl;
+                std::cout << "ratedMin: " << pdr->rated_min.value_u16
+                          << std::endl;
+                break;
+            case PLDM_RANGE_FIELD_FORMAT_SINT16:
+                std::cout << "nominalValue: " << pdr->nominal_value.value_s16
+                          << std::endl;
+                std::cout << "normalMax: " << pdr->normal_max.value_s16
+                          << std::endl;
+                std::cout << "normalMin: " << pdr->normal_min.value_s16
+                          << std::endl;
+                std::cout << "ratedMax: " << pdr->rated_max.value_s16
+                          << std::endl;
+                std::cout << "ratedMin: " << pdr->rated_min.value_s16
+                          << std::endl;
+                break;
+            case PLDM_RANGE_FIELD_FORMAT_UINT32:
+                std::cout << "nominalValue: " << pdr->nominal_value.value_u32
+                          << std::endl;
+                std::cout << "normalMax: " << pdr->normal_max.value_u32
+                          << std::endl;
+                std::cout << "normalMin: " << pdr->normal_min.value_u32
+                          << std::endl;
+                std::cout << "ratedMax: " << pdr->rated_max.value_u32
+                          << std::endl;
+                std::cout << "ratedMin: " << pdr->rated_min.value_u32
+                          << std::endl;
+                break;
+            case PLDM_RANGE_FIELD_FORMAT_SINT32:
+                std::cout << "nominalValue: " << pdr->nominal_value.value_s32
+                          << std::endl;
+                std::cout << "normalMax: " << pdr->normal_max.value_s32
+                          << std::endl;
+                std::cout << "normalMin: " << pdr->normal_min.value_s32
+                          << std::endl;
+                std::cout << "ratedMax: " << pdr->rated_max.value_s32
+                          << std::endl;
+                std::cout << "ratedMin: " << pdr->rated_min.value_s32
+                          << std::endl;
+                break;
+            case PLDM_RANGE_FIELD_FORMAT_REAL32:
+                std::cout << "nominalValue: " << pdr->nominal_value.value_f32
+                          << std::endl;
+                std::cout << "normalMax: " << pdr->normal_max.value_f32
+                          << std::endl;
+                std::cout << "normalMin: " << pdr->normal_min.value_f32
+                          << std::endl;
+                std::cout << "ratedMax: " << pdr->rated_max.value_f32
+                          << std::endl;
+                std::cout << "ratedMin: " << pdr->rated_min.value_f32
+                          << std::endl;
+                break;
+            default:
+                break;
+        }
+    }
+
+    void printStateEffecterPDR(uint8_t* data)
+    {
+        if (data == NULL)
+        {
+            return;
+        }
+
+        struct pldm_state_effecter_pdr* pdr =
+            (struct pldm_state_effecter_pdr*)data;
+        printEffecterHdrPDR(&pdr->hdr);
+
+        std::cout << "PLDMTerminusHandle: " << pdr->terminus_handle
+                  << std::endl;
+        std::cout << "effecterID: " << pdr->effecter_id << std::endl;
+        std::cout << "entityType: " << pdr->entity_type << std::endl;
+        std::cout << "entityInstanceNumber: " << pdr->entity_instance
+                  << std::endl;
+        std::cout << "containerID: " << pdr->container_id << std::endl;
+        std::cout << "effecterSemanticID: " << pdr->effecter_semantic_id
+                  << std::endl;
+        std::cout << "effecterInit: " << unsigned(pdr->effecter_init)
+                  << std::endl;
+        std::cout << "effecterDescriptionPDR: "
+                  << (unsigned(pdr->has_description_pdr) ? "true" : "false")
+                  << std::endl;
+        std::cout << "compositeEffecterCount: "
+                  << unsigned(pdr->composite_effecter_count) << std::endl;
+
+        for (size_t i = 0; i < pdr->composite_effecter_count; ++i)
+        {
+            struct state_effecter_possible_states* state =
+                (struct state_effecter_possible_states*)pdr->possible_states +
+                i * sizeof(state_effecter_possible_states);
+            std::cout << "stateSetID: " << state->state_set_id << std::endl;
+            std::cout << "possibleStatesSize: "
+                      << unsigned(state->possible_states_size) << std::endl;
+            bitfield8_t* bf = reinterpret_cast<bitfield8_t*>(state->states);
+            std::cout << "possibleStates: " << unsigned(bf->byte) << std::endl;
+        }
+    }
+
+    void printPDRMsg(const uint32_t nextRecordHndl, const uint16_t respCnt,
+                     uint8_t* data)
+    {
+        if (data == NULL)
+        {
+            return;
+        }
+
+        std::cout << "nextRecordHandle: " << nextRecordHndl << std::endl;
+        std::cout << "responseCount: " << respCnt << std::endl;
+
+        struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
+        std::cout << "recordHandle: " << pdr->record_handle << std::endl;
+        std::cout << "PDRHeaderVersion: " << unsigned(pdr->version)
+                  << std::endl;
+        std::cout << "PDRType: " << unsigned(pdr->type) << std::endl;
+        std::cout << "recordChangeNumber: " << pdr->record_change_num
+                  << std::endl;
+        std::cout << "dataLength: " << pdr->length << std::endl << std::endl;
+
+        switch (pdr->type)
+        {
+            case PLDM_NUMERIC_EFFECTER_PDR:
+                printNumericEffecterPDR(data);
+                break;
+            case PLDM_STATE_EFFECTER_PDR:
+                printStateEffecterPDR(data);
+                break;
+            case PLDM_PDR_ENTITY_ASSOCIATION:
+                printPDREntityAssociation(data);
+                break;
+            case PLDM_PDR_FRU_RECORD_SET:
+                printPDRFruRecordSet(data);
+                break;
+            default:
+                break;
+        }
+    }
+
+  private:
+    uint32_t recordHandle;
+};
+
+class SetStateEffecter : public CommandInterface
+{
+  public:
+    ~SetStateEffecter() = default;
+    SetStateEffecter() = delete;
+    SetStateEffecter(const SetStateEffecter&) = delete;
+    SetStateEffecter(SetStateEffecter&&) = default;
+    SetStateEffecter& operator=(const SetStateEffecter&) = delete;
+    SetStateEffecter& operator=(SetStateEffecter&&) = default;
+
+    // compositeEffecterCount(value: 0x01 to 0x08) * stateField(2)
+    static constexpr auto maxEffecterDataSize = 16;
+
+    // compositeEffecterCount(value: 0x01 to 0x08)
+    static constexpr auto minEffecterCount = 1;
+    static constexpr auto maxEffecterCount = 8;
+    explicit SetStateEffecter(const char* type, const char* name,
+                              CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option(
+               "-i, --id", effecterId,
+               "A handle that is used to identify and access the effecter")
+            ->required();
+        app->add_option("-c, --count", effecterCount,
+                        "The number of individual sets of effecter information")
+            ->required();
+        app->add_option(
+               "-d,--data", effecterData,
+               "Set effecter state data\n"
+               "eg: requestSet0 effecterState0 noChange1 dummyState1 ...")
+            ->required();
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(
+            sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        if (effecterCount > maxEffecterCount ||
+            effecterCount < minEffecterCount)
+        {
+            std::cerr << "Request Message Error: effecterCount size "
+                      << effecterCount << "is invalid\n";
+            auto rc = PLDM_ERROR_INVALID_DATA;
+            return {rc, requestMsg};
+        }
+
+        if (effecterData.size() > maxEffecterDataSize)
+        {
+            std::cerr << "Request Message Error: effecterData size "
+                      << effecterData.size() << "is invalid\n";
+            auto rc = PLDM_ERROR_INVALID_DATA;
+            return {rc, requestMsg};
+        }
+
+        auto stateField = parseEffecterData(effecterData, effecterCount);
+        if (!stateField)
+        {
+            std::cerr << "Failed to parse effecter data, effecterCount size "
+                      << effecterCount << "\n";
+            auto rc = PLDM_ERROR_INVALID_DATA;
+            return {rc, requestMsg};
+        }
+
+        auto rc = encode_set_state_effecter_states_req(
+            instanceId, effecterId, effecterCount, stateField->data(), request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t completionCode = 0;
+        auto rc = decode_set_state_effecter_states_resp(
+            responsePtr, payloadLength, &completionCode);
+
+        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
+            return;
+        }
+
+        std::cout << "SetStateEffecterStates: SUCCESS" << std::endl;
+    }
+
+  private:
+    uint16_t effecterId;
+    uint8_t effecterCount;
+    std::vector<uint8_t> effecterData;
+};
+
+class SetNumericEffecterValue : public CommandInterface
+{
+  public:
+    ~SetNumericEffecterValue() = default;
+    SetNumericEffecterValue() = delete;
+    SetNumericEffecterValue(const SetNumericEffecterValue&) = delete;
+    SetNumericEffecterValue(SetNumericEffecterValue&&) = default;
+    SetNumericEffecterValue& operator=(const SetNumericEffecterValue&) = delete;
+    SetNumericEffecterValue& operator=(SetNumericEffecterValue&&) = default;
+
+    explicit SetNumericEffecterValue(const char* type, const char* name,
+                                     CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option(
+               "-i, --id", effecterId,
+               "A handle that is used to identify and access the effecter")
+            ->required();
+        app->add_option("-s, --size", effecterDataSize,
+                        "The bit width and format of the setting value for the "
+                        "effecter. enum value: {uint8, sint8, uint16, sint16, "
+                        "uint32, sint32}\n")
+            ->required();
+        app->add_option("-d,--data", maxEffecterValue,
+                        "The setting value of numeric effecter being "
+                        "requested\n")
+            ->required();
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(
+            sizeof(pldm_msg_hdr) +
+            PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3);
+
+        uint8_t* effecterValue = (uint8_t*)&maxEffecterValue;
+
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+        size_t payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES;
+
+        if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16 ||
+            effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16)
+        {
+            payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1;
+        }
+        if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32 ||
+            effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32)
+        {
+            payload_length = PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3;
+        }
+        auto rc = encode_set_numeric_effecter_value_req(
+            0, effecterId, effecterDataSize, effecterValue, request,
+            payload_length);
+
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t completionCode = 0;
+        auto rc = decode_set_numeric_effecter_value_resp(
+            responsePtr, payloadLength, &completionCode);
+
+        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)completionCode
+                      << std::endl;
+            return;
+        }
+
+        std::cout << "SetNumericEffecterValue: SUCCESS" << std::endl;
+    }
+
+  private:
+    uint16_t effecterId;
+    uint8_t effecterDataSize;
+    uint64_t maxEffecterValue;
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto platform = app.add_subcommand("platform", "platform type command");
+    platform->require_subcommand(1);
+
+    auto getPDR =
+        platform->add_subcommand("GetPDR", "get platform descriptor records");
+    commands.push_back(std::make_unique<GetPDR>("platform", "getPDR", getPDR));
+
+    auto setStateEffecterStates = platform->add_subcommand(
+        "SetStateEffecterStates", "set effecter states");
+    commands.push_back(std::make_unique<SetStateEffecter>(
+        "platform", "setStateEffecterStates", setStateEffecterStates));
+
+    auto setNumericEffecterValue = platform->add_subcommand(
+        "SetNumericEffecterValue", "set the value for a PLDM Numeric Effecter");
+    commands.push_back(std::make_unique<SetNumericEffecterValue>(
+        "platform", "setNumericEffecterValue", setNumericEffecterValue));
+}
+
+} // namespace platform
+} // namespace pldmtool
diff --git a/pldmtool/pldm_platform_cmd.hpp b/pldmtool/pldm_platform_cmd.hpp
new file mode 100644
index 0000000..45f15ba
--- /dev/null
+++ b/pldmtool/pldm_platform_cmd.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <CLI/CLI.hpp>
+
+namespace pldmtool
+{
+
+namespace platform
+{
+
+void registerCommand(CLI::App& app);
+
+} // namespace platform
+
+} // namespace pldmtool
diff --git a/pldmtool/pldmtool.cpp b/pldmtool/pldmtool.cpp
new file mode 100644
index 0000000..4b65b2a
--- /dev/null
+++ b/pldmtool/pldmtool.cpp
@@ -0,0 +1,82 @@
+#include "pldm_base_cmd.hpp"
+#include "pldm_bios_cmd.hpp"
+#include "pldm_cmd_helper.hpp"
+#include "pldm_fru_cmd.hpp"
+#include "pldm_platform_cmd.hpp"
+#include "pldmtool/oem/ibm/pldm_host_cmd.hpp"
+
+#include <CLI/CLI.hpp>
+
+namespace pldmtool
+{
+
+namespace raw
+{
+
+using namespace pldmtool::helper;
+
+namespace
+{
+std::vector<std::unique_ptr<CommandInterface>> commands;
+}
+
+class RawOp : public CommandInterface
+{
+  public:
+    ~RawOp() = default;
+    RawOp() = delete;
+    RawOp(const RawOp&) = delete;
+    RawOp(RawOp&&) = default;
+    RawOp& operator=(const RawOp&) = delete;
+    RawOp& operator=(RawOp&&) = default;
+
+    explicit RawOp(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option("-d,--data", rawData, "raw data")
+            ->required()
+            ->expected(-3);
+    }
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+
+    {
+        return {PLDM_SUCCESS, rawData};
+    }
+
+    void parseResponseMsg(pldm_msg* /* responsePtr */,
+                          size_t /* payloadLength */) override
+    {}
+
+  private:
+    std::vector<uint8_t> rawData;
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto raw =
+        app.add_subcommand("raw", "send a raw request and print response");
+    commands.push_back(std::make_unique<RawOp>("raw", "raw", raw));
+}
+
+} // namespace raw
+} // namespace pldmtool
+
+int main(int argc, char** argv)
+{
+
+    CLI::App app{"PLDM requester tool for OpenBMC"};
+    app.require_subcommand(1)->ignore_case();
+
+    pldmtool::raw::registerCommand(app);
+    pldmtool::base::registerCommand(app);
+    pldmtool::bios::registerCommand(app);
+    pldmtool::platform::registerCommand(app);
+    pldmtool::fru::registerCommand(app);
+
+#ifdef OEM_IBM
+    pldmtool::oem_ibm::power_host::registerCommand(app);
+#endif
+
+    CLI11_PARSE(app, argc, argv);
+    return 0;
+}