tool: Refactor base type Commands

Each command will be implemented as a CLI subcommand
command handers registration process:

    CLI::App app;
    auto base = app.add_subcommand("base");
    auto GetPLDMVersion = base->add_subcommand("GetPLDMVersion");
    /* register callback for GetPLDMVersion Command */
    GetPLDMVersion->callback(exec());
    CLI11_PARSER();

Each command will be implemented as a class. To avoid duplicate,
An interface class is abstracted as the base class for commands.

CommandInterface
{
	CommandInterface(CLI::App* app){
		app->callback([&](){exec();}) //register exec() to CLI11
	}
	virtual createRequestMsg();
	virtual parseResponseMsg();
	exec(){
		createRequestMsg();
		send_recv();
		parseResponseMsg();
	}
};

GetPLDMVersion : public CommandInterface
{
	GetPLDMVersion(CLI::App *app){
		app->add_option();  // add options for this command
	}
	...
}

Then, the main is like below:

int main()
{
	CLI::App app{"PLDM requester tool for OpenBMC"};
	auto base = app.add_subcommand("base");
	auto version = base->add_subcommand("GetPLDMVersion");
	GetPLDMVersion getPLDMVersion(version);
	CLI11_PARSE(app, argc, argv);
}

Tested:

root@fp5280g2:~# pldmtool base GetPLDMTypes
Encode request successfully
Request Message:
08 01 80 00 04
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 5
Total length:5
Loopback response message:
08 01 80 00 04
On first recv(),response == request : RC = 0
Total length: 14
Shutdown Socket successful :  RC = 0
Response Message:
08 01 00 00 04 00 0d 00 00 00 00 00 00 00
Supported types: 0(base) 2(platform) 3(bios)

root@fp5280g2:~# pldmtool base GetPLDMVersion -t platform
Encode request successfully
Request Message:
08 01 80 00 03 00 00 00 00 01 02
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 11
Total length:11
Loopback response message:
08 01 80 00 03 00 00 00 00 01 02
On first recv(),response == request : RC = 0
Total length: 15
Shutdown Socket successful :  RC = 0
Response Message:
08 01 00 00 03 00 00 00 00 00 05 f1 f1 f1 00
Type 2(platform): 1.1.1

root@fp5280g2:~# pldmtool raw -d 0x80 0x00 0x04
Encode request successfully
Request Message:
08 01 80 00 04
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 5
Total length:5
Loopback response message:
08 01 80 00 04
On first recv(),response == request : RC = 0
Total length: 14
Shutdown Socket successful :  RC = 0
Response Message:
08 01 00 00 04 00 0d 00 00 00 00 00 00 00

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I658b2c8094e9e5d972d786b26f9f8d52bc011981
diff --git a/tool/handler.hpp b/tool/handler.hpp
deleted file mode 100644
index 086c132..0000000
--- a/tool/handler.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include "pldm_base_cmd.hpp"
-
-#include <functional>
-#include <map>
-#include <string>
-#include <typeindex>
-
-using Cmd = std::string;
-using Args = std::vector<std::string>;
-class Handler
-{
-  public:
-    const std::map<Cmd, std::function<void(Args&&)>> dispatcher{
-        {"GetPLDMTypes",
-         [](Args&& args) { return getPLDMTypes(std::move(args)); }},
-        {"GetPLDMVersion",
-         [](Args&& args) { return getPLDMVersion(std::move(args)); }},
-        {"HandleRawOp",
-         [](Args&& args) { return handleRawOp(std::move(args)); }}};
-};
diff --git a/tool/pldm_base_cmd.cpp b/tool/pldm_base_cmd.cpp
index 7c199c1..601635c 100644
--- a/tool/pldm_base_cmd.cpp
+++ b/tool/pldm_base_cmd.cpp
@@ -2,258 +2,167 @@
 
 #include "pldm_cmd_helper.hpp"
 
+#include <map>
+#include <memory>
 #include <string>
+#include <vector>
 
-constexpr uint8_t PLDM_ENTITY_ID = 8;
-constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
-constexpr uint8_t PLDM_LOCAL_INSTANCE_ID = 0;
+#include "libpldm/utils.h"
 
-using namespace std;
-
-/*
- * Main function that handles the GetPLDMTypes response callback via mctp
- *
- */
-void getPLDMTypes(vector<std::string>&& /*args*/)
+namespace pldmtool
 {
-    // Create and encode the request message
-    vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
-                               sizeof(MCTP_MSG_TYPE_PLDM) +
-                               sizeof(PLDM_ENTITY_ID));
-    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
 
-    // Encode the get_types request message
-    uint8_t instanceId = PLDM_LOCAL_INSTANCE_ID;
-    auto returnCode = encode_get_types_req(instanceId, request);
-    if (returnCode)
-    {
-        cerr << "Failed to encode request msg for GetPLDMType : RC = "
-             << returnCode << endl;
-        return;
-    }
-    cout << "Encoded request succesfully : RC = " << returnCode << endl;
-
-    // Insert the PLDM message type and EID at the begining of the request msg.
-    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
-    requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
-
-    cout << "Request Message:" << endl;
-    printBuffer(requestMsg);
-
-    // Create the response message
-    vector<uint8_t> responseMsg;
-
-    // Compares the response with request packet on first socket recv() call.
-    // If above condition is qualified then, reads the actual response from
-    // the socket to output buffer responseMsg.
-    returnCode = mctpSockSendRecv(requestMsg, responseMsg);
-    if (!returnCode)
-    {
-        cout << "Socket recv() successful : RC = " << returnCode << endl;
-        cout << "Response Message : " << endl;
-        printBuffer(responseMsg);
-    }
-    else
-    {
-        cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
-        return;
-    }
-}
-
-/*
- * Main function that handles the GetPLDMVersion response callback via mctp
- *
- */
-void getPLDMVersion(vector<std::string>&& args)
+namespace base
 {
-    // Create a request packet
-    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
-                                    PLDM_GET_VERSION_REQ_BYTES);
-    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
 
-    uint8_t pldmType = 0x0;
-
-    if (!args[1].c_str())
-    {
-        cout << "Mandatory argument PLDM Command Type not provided!" << endl;
-        cout << "Run pldmtool --help for more information" << endl;
-        return;
-    }
-
-    if (!strcasecmp(args[1].c_str(), "base"))
-    {
-        cout << "PLDM Type requested : " << args[1] << endl;
-        pldmType = PLDM_BASE;
-    }
-    else if (!strcasecmp(args[1].c_str(), "bios"))
-    {
-        cout << "PLDM Type requested : " << args[1] << endl;
-        pldmType = PLDM_BIOS;
-    }
-    else if (!strcasecmp(args[1].c_str(), "fru"))
-    {
-        cout << "PLDM Type requested : " << args[1] << endl;
-        pldmType = PLDM_FRU;
-    }
-    else if (!strcasecmp(args[1].c_str(), "oem"))
-    {
-        cout << "PLDM Type requested : " << args[1] << endl;
-        pldmType = PLDM_OEM;
-    }
-    else
-    {
-        cerr << "Unsupported pldm command type OR not supported yet : "
-             << args[1] << endl;
-        return;
-    }
-
-    uint8_t instanceId = PLDM_LOCAL_INSTANCE_ID;
-    uint32_t transferHandle = 0x0;
-    transfer_op_flag opFlag = PLDM_GET_FIRSTPART;
-
-    // encode the get_version request
-    auto returnCode = encode_get_version_req(instanceId, transferHandle, opFlag,
-                                             pldmType, request);
-    if (returnCode)
-    {
-        cerr << "Failed to encode request msg for GetPLDMVersion. RC = "
-             << returnCode << endl;
-        return;
-    }
-    cout << "Encoded request succesfully : RC = " << returnCode << endl;
-
-    // Insert the PLDM message type and EID at the begining of the request msg.
-    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
-    requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
-
-    cout << "Request Message:" << endl;
-    printBuffer(requestMsg);
-
-    // Create the response message
-    vector<uint8_t> responseMsg;
-
-    // Compares the response with request packet on first socket recv() call.
-    // If above condition is qualified then, reads the actual response from
-    // the socket to output buffer responseMsg.
-    returnCode = mctpSockSendRecv(requestMsg, responseMsg);
-    if (!returnCode)
-    {
-        cout << "Socket recv() successful : RC = " << returnCode << endl;
-        cout << "Response Message:" << endl;
-        printBuffer(responseMsg);
-    }
-    else
-    {
-        cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
-        return;
-    }
-}
-
-/*
- * Main function that handles the PLDM raw command response callback via mctp
- *
- */
-void handleRawOp(vector<std::string>&& args)
+namespace
 {
-    // Minimu 3 bytes of header data needs to passed. else its a invalid request
-    if (size(args) < 3)
+
+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},   {"oem", PLDM_OEM},
+};
+
+} // 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
     {
-        cerr << "Not enough arguments passed."
-                " Minimum, need to pass PLDM header raw data"
-             << endl;
-        return;
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+        auto rc = encode_get_types_req(PLDM_LOCAL_INSTANCE_ID, request);
+        return {rc, requestMsg};
     }
 
-    // Create a request packet and initialize it
-    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
-    requestMsg.clear();
-
-    // Read the raw data passed in the command line
-    // Form request message from the raw data passed
-    for (auto&& rawByte : args)
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
     {
-        requestMsg.insert(requestMsg.end(), stoi(rawByte, nullptr, 16));
-    }
-
-    // Validating the payload raw data based on pldm command type
-    uint8_t pldmCmd = requestMsg[2];
-    switch (pldmCmd)
-    {
-        case PLDM_GET_PLDM_VERSION:
-            if (size(requestMsg) !=
-                (sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES))
-            {
-                cerr << "Not enough raw data provided." << endl;
-                cerr << "Total length can be = 3 bytes of header + 6 bytes"
-                        " for payload. Please refer spec for details"
-                     << endl;
-                return;
-            }
-            break;
-        case PLDM_GET_TID:
-        case PLDM_GET_PLDM_TYPES:
-            if (size(requestMsg) != sizeof(pldm_msg_hdr))
-            {
-                cerr << "Total length can be = 3 bytes of header + 0 bytes"
-                        " for payload. Please refer spec for details"
-                     << endl;
-                return;
-            }
-            break;
-        case PLDM_GET_PLDM_COMMANDS:
-            if (size(requestMsg) !=
-                sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES)
-            {
-                cerr << "Total length can be = 3 bytes of header + 5 bytes"
-                        " for payload. Please refer spec for details"
-                     << endl;
-                return;
-            }
-            break;
-        case PLDM_SET_STATE_EFFECTER_STATES:
-            // payload size depends on comp_effecter_count
-            // if count=1 then, request size will be 8 bytes including header
-            // if count=9 then, request size will be 19 bytes including header
-            if ((size(requestMsg) < 8) ||
-                (size(requestMsg) >
-                 sizeof(pldm_msg_hdr) +
-                     PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES))
-            {
-                cerr << "Total length can be = 3 bytes of header + min/max 8/19"
-                        " bytes for payload. Please refer spec for details"
-                     << endl;
-                return;
-            }
-            break;
-        default:
-            cerr << "Command Not supported/implemented : " << args[2] << endl;
-            cerr << "Contact backend Team" << endl;
+        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 << std::endl;
             return;
+        }
+
+        printPldmTypes(types);
     }
 
-    // Add the MCTP type and PLDM entity id at the end
-    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
-    requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
-
-    cout << "Request Message" << endl;
-    printBuffer(requestMsg);
-
-    // Create the response message
-    vector<uint8_t> responseMsg;
-
-    // Compares the response with request packet on first socket recv() call.
-    // If above condition is qualified then, reads the actual response from
-    // the socket to output buffer responseMsg.
-    int returnCode = mctpSockSendRecv(requestMsg, responseMsg);
-    if (!returnCode)
+  private:
+    void printPldmTypes(std::vector<bitfield8_t>& types)
     {
-        cout << "Socket recv() successful : RC = " << returnCode << endl;
-        cout << "Response Message:" << endl;
-        printBuffer(responseMsg);
+        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;
     }
-    else
+};
+
+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)
     {
-        cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
-        return;
+        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(PLDM_LOCAL_INSTANCE_ID, 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 << std::endl;
+            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;
+};
+
+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));
 }
+
+} // namespace base
+} // namespace pldmtool
diff --git a/tool/pldm_base_cmd.hpp b/tool/pldm_base_cmd.hpp
index d709ede..b465963 100644
--- a/tool/pldm_base_cmd.hpp
+++ b/tool/pldm_base_cmd.hpp
@@ -1,37 +1,14 @@
 #pragma once
 
-#ifndef PLDM_BASE_CMD_H
-#define PLDM_BASE_CMD_H
+#include <CLI/CLI.hpp>
 
-#include "pldm_cmd_helper.hpp"
+namespace pldmtool
+{
 
-/** @brief Handler for GetPLDMTypes command
- *
- *  @param[in]  args - Argument to be passed to the handler.
- *                     Optional argument.
- *
- *  @return - None
- */
-void getPLDMTypes(std::vector<std::string>&& args);
+namespace base
+{
 
-/** @brief Handler for GetPLDMVersion command
- *
- *
- *  @param[in]  args - Argument to be passed to the handler
- *              e.g :  PLDM Command Type : base, bios etc.
- *
- *  @return - None
- */
-void getPLDMVersion(std::vector<std::string>&& args);
+void registerCommand(CLI::App& app);
+}
 
-/** @brief Handler for Raw PLDM commands
- *
- *
- *  @param[in]  args - Argument to be passed to the handler
- *              e.g :  PLDM raw commands.
- *
- *  @return - None
- */
-void handleRawOp(std::vector<std::string>&& args);
-
-#endif /* PLDM_BASE_CMD_H */
+} // namespace pldmtool
\ No newline at end of file
diff --git a/tool/pldm_cmd_helper.cpp b/tool/pldm_cmd_helper.cpp
index eea2759..b9ddbf5 100644
--- a/tool/pldm_cmd_helper.cpp
+++ b/tool/pldm_cmd_helper.cpp
@@ -1,9 +1,10 @@
 #include "pldm_cmd_helper.hpp"
 
-constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
-constexpr uint8_t PLDM_ENTITY_ID = 8;
+namespace pldmtool
+{
 
-using namespace std;
+namespace helper
+{
 
 /*
  * print the input buffer
@@ -20,7 +21,7 @@
                        << " ";
         }
     }
-    cout << tempStream.str().c_str() << endl;
+    std::cout << tempStream.str() << std::endl;
 }
 
 /*
@@ -37,10 +38,12 @@
     if (-1 == sockFd)
     {
         returnCode = -errno;
-        cerr << "Failed to create the socket : RC = " << sockFd << endl;
+        std::cerr << "Failed to create the socket : RC = " << sockFd
+                  << std::endl;
         return returnCode;
     }
-    cout << "Success in creating the socket : RC = " << sockFd << endl;
+    std::cout << "Success in creating the socket : RC = " << sockFd
+              << std::endl;
 
     struct sockaddr_un addr
     {
@@ -55,43 +58,48 @@
     if (-1 == result)
     {
         returnCode = -errno;
-        cerr << "Failed to connect to socket : RC = " << returnCode << endl;
+        std::cerr << "Failed to connect to socket : RC = " << returnCode
+                  << std::endl;
         return returnCode;
     }
-    cout << "Success in connecting to socket : RC = " << returnCode << endl;
+    std::cout << "Success in connecting to socket : RC = " << returnCode
+              << std::endl;
 
     auto pldmType = MCTP_MSG_TYPE_PLDM;
     result = write(socketFd(), &pldmType, sizeof(pldmType));
     if (-1 == result)
     {
         returnCode = -errno;
-        cerr << "Failed to send message type as pldm to mctp : RC = "
-             << returnCode << endl;
+        std::cerr << "Failed to send message type as pldm to mctp : RC = "
+                  << returnCode << std::endl;
         return returnCode;
     }
-    cout << "Success in sending message type as pldm to mctp : RC = "
-         << returnCode << endl;
+    std::cout << "Success in sending message type as pldm to mctp : RC = "
+              << returnCode << std::endl;
 
     result = send(socketFd(), requestMsg.data(), requestMsg.size(), 0);
     if (-1 == result)
     {
         returnCode = -errno;
-        cerr << "Write to socket failure : RC = " << returnCode << endl;
+        std::cerr << "Write to socket failure : RC = " << returnCode
+                  << std::endl;
         return returnCode;
     }
-    cout << "Write to socket successful : RC = " << result << endl;
+    std::cout << "Write to socket successful : RC = " << result << std::endl;
 
     // Read the response from socket
     ssize_t peekedLength = recv(socketFd(), nullptr, 0, MSG_TRUNC | MSG_PEEK);
     if (0 == peekedLength)
     {
-        cerr << "Socket is closed : peekedLength = " << peekedLength << endl;
+        std::cerr << "Socket is closed : peekedLength = " << peekedLength
+                  << std::endl;
         return returnCode;
     }
     else if (peekedLength <= -1)
     {
         returnCode = -errno;
-        cerr << "recv() system call failed : RC = " << returnCode << endl;
+        std::cerr << "recv() system call failed : RC = " << returnCode
+                  << std::endl;
         return returnCode;
     }
     else
@@ -103,16 +111,16 @@
                  peekedLength, 0);
         if (recvDataLength == peekedLength)
         {
-            cout << "Total length:" << recvDataLength << endl;
-            cout << "Loopback response message:" << endl;
+            std::cout << "Total length:" << recvDataLength << std::endl;
+            std::cout << "Loopback response message:" << std::endl;
             printBuffer(loopBackRespMsg);
         }
         else
         {
-            cerr << "Failure to read peeked length packet : RC = " << returnCode
-                 << endl;
-            cerr << "peekedLength: " << peekedLength << endl;
-            cerr << "Total length: " << recvDataLength << endl;
+            std::cerr << "Failure to read peeked length packet : RC = "
+                      << returnCode << std::endl;
+            std::cerr << "peekedLength: " << peekedLength << std::endl;
+            std::cerr << "Total length: " << recvDataLength << std::endl;
             return returnCode;
         }
 
@@ -122,8 +130,8 @@
         uint8_t request = hdr->request;
         if (request == PLDM_REQUEST)
         {
-            cout << "On first recv(),response == request : RC = " << returnCode
-                 << endl;
+            std::cout << "On first recv(),response == request : RC = "
+                      << returnCode << std::endl;
             ssize_t peekedLength =
                 recv(socketFd(), nullptr, 0, MSG_PEEK | MSG_TRUNC);
 
@@ -133,19 +141,19 @@
                      peekedLength, 0);
             if (recvDataLength == peekedLength)
             {
-                cout << "Total length: " << recvDataLength << endl;
+                std::cout << "Total length: " << recvDataLength << std::endl;
             }
             else
             {
-                cerr << "Failure to read response length packet: length = "
-                     << recvDataLength << endl;
+                std::cerr << "Failure to read response length packet: length = "
+                          << recvDataLength << std::endl;
                 return returnCode;
             }
         }
         else
         {
-            cerr << "On first recv(),request != response : RC = " << returnCode
-                 << endl;
+            std::cerr << "On first recv(),request != response : RC = "
+                      << returnCode << std::endl;
             return returnCode;
         }
     }
@@ -153,10 +161,53 @@
     if (-1 == returnCode)
     {
         returnCode = -errno;
-        cerr << "Failed to shutdown the socket : RC = " << returnCode << endl;
+        std::cerr << "Failed to shutdown the socket : RC = " << returnCode
+                  << std::endl;
         return returnCode;
     }
 
-    cout << "Shutdown Socket successful :  RC = " << returnCode << endl;
+    std::cout << "Shutdown Socket successful :  RC = " << returnCode
+              << std::endl;
     return PLDM_SUCCESS;
 }
+
+void CommandInterface::exec()
+{
+    auto [rc, requestMsg] = createRequestMsg();
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Failed to encode request message for " << pldmType << ":"
+                  << commandName << " rc = " << rc << std::endl;
+        return;
+    }
+
+    std::cout << "Encode request successfully" << std::endl;
+
+    // Insert the PLDM message type and EID at the begining of the request msg.
+    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
+    requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
+
+    std::cout << "Request Message:" << std::endl;
+    printBuffer(requestMsg);
+
+    std::vector<uint8_t> responseMsg;
+    rc = mctpSockSendRecv(requestMsg, responseMsg);
+
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Failed to receive from socket: RC = " << rc << std::endl;
+        return;
+    }
+
+    std::cout << "Response Message:" << std::endl;
+    printBuffer(responseMsg);
+
+    auto responsePtr = reinterpret_cast<struct pldm_msg*>(
+        responseMsg.data() + 2 /*skip the mctp header*/);
+    parseResponseMsg(responsePtr, responseMsg.size() -
+                                      2 /*skip the mctp header*/ -
+                                      sizeof(pldm_msg_hdr));
+}
+
+} // namespace helper
+} // namespace pldmtool
\ No newline at end of file
diff --git a/tool/pldm_cmd_helper.hpp b/tool/pldm_cmd_helper.hpp
index 8032c9a..a162de4 100644
--- a/tool/pldm_cmd_helper.hpp
+++ b/tool/pldm_cmd_helper.hpp
@@ -1,8 +1,5 @@
 #pragma once
 
-#ifndef PLDM_CMD_HELPER_H
-#define PLDM_CMD_HELPER_H
-
 #include "libpldmresponder/utils.hpp"
 
 #include <err.h>
@@ -10,14 +7,25 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <CLI/CLI.hpp>
 #include <cstring>
 #include <iomanip>
 #include <iostream>
+#include <utility>
 
 #include "libpldm/base.h"
 #include "libpldm/platform.h"
 
+namespace pldmtool
+{
+
+namespace helper
+{
+
 using namespace pldm::responder::utils;
+constexpr uint8_t PLDM_ENTITY_ID = 8;
+constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
+constexpr uint8_t PLDM_LOCAL_INSTANCE_ID = 0;
 
 /** @brief Print the buffer
  *
@@ -39,4 +47,29 @@
 int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg,
                      std::vector<uint8_t>& responseMsg);
 
-#endif
+class CommandInterface
+{
+  public:
+    explicit CommandInterface(const char* type, const char* name,
+                              CLI::App* app) :
+        pldmType(type),
+        commandName(name)
+    {
+        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;
+
+    void exec();
+
+  private:
+    const std::string pldmType;
+    const std::string commandName;
+};
+
+} // namespace helper
+} // namespace pldmtool
diff --git a/tool/pldmtool.cpp b/tool/pldmtool.cpp
index 54287d5..7244e47 100644
--- a/tool/pldmtool.cpp
+++ b/tool/pldmtool.cpp
@@ -1,108 +1,72 @@
-#include "handler.hpp"
+#include "pldm_base_cmd.hpp"
+#include "pldm_cmd_helper.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();
 
-    // TODO: To enable it later
-    // bool verbose_flag = false;
-    // app.add_flag("-v, --verbose", verbose_flag, "Output debug logs ");
-    std::vector<std::string> rawCmd{};
-    app.add_option("-r, --raw", rawCmd,
-                   "Send a RAW PLDM request and print response");
-
-    auto base = app.add_subcommand("BASE", "PLDM Command Type = BASE");
-    std::vector<std::string> args{};
-    base->add_option("-c, --command", args,
-                     "PLDM request command \n"
-                     "[GetPLDMTypes] Get PLDM Type \n"
-                     "[GetPLDMVersion] Get PLDM Version");
-
-    auto bios = app.add_subcommand("BIOS", "PLDM Command Type = BIOS");
-    bios->add_option("-c, --command", args, "PLDM request command");
-
-    auto oem = app.add_subcommand("OEM", "PLDM Command Type = OEM");
-    oem->add_option("-c, --command", args, "PLDM request command");
+    pldmtool::raw::registerCommand(app);
+    pldmtool::base::registerCommand(app);
 
     CLI11_PARSE(app, argc, argv);
-
-    std::string cmdName;
-    int rc = 0;
-
-    if (argc < 2)
-    {
-        std::cerr << "Run pldmtool --help for more information" << std::endl;
-        return -1;
-    }
-
-    if (memcmp(argv[1], "--raw", strlen(argv[1])) != 0 &&
-        memcmp(argv[1], "-r", strlen(argv[1])) != 0)
-    {
-        // Parse args to program
-        if (args.size() == 0)
-        {
-            std::cerr << "Run pldmtool --help for more information"
-                      << std::endl;
-            return -1;
-        }
-        cmdName = args[0];
-    }
-    else
-    {
-        if (rawCmd.size() == 0)
-        {
-            std::cerr << "Run pldmtool --help for more information"
-                      << std::endl;
-            return -1;
-        }
-
-        // loop through the remaining argument list
-        for (auto&& item : rawCmd)
-        {
-
-            if (item[0] == '0' && (item[1] == 'x' || item[1] == 'X'))
-            {
-
-                // Erase 0x from input
-                item.erase(0, 2);
-
-                // Check for hex input value validity
-                if (std::all_of(item.begin(), item.end(), ::isxdigit))
-                {
-
-                    // Parse args to program
-                    cmdName = "HandleRawOp";
-                }
-                else
-                {
-                    std::cerr << item << " contains non hex digits. Re-enter"
-                              << std::endl;
-                    return -1;
-                }
-            }
-            else
-            {
-                std::cerr << item << " Input hex value starting with 0x "
-                          << std::endl;
-                return -1;
-            }
-        }
-        args = rawCmd;
-    }
-
-    Handler handler;
-    try
-    {
-        handler.dispatcher.at(cmdName)(std::move(args));
-    }
-    catch (const std::out_of_range& e)
-    {
-        std::cerr << cmdName << " is not supported!" << std::endl;
-        return -1;
-    }
-
-    return rc;
+    return 0;
 }