pldmtool: Add commands

Implement sending out and processing the response of the following commands : GetPDR, SetStateEffecterStates, SetDateTime

Tested:
 $ pldmtool platform GetPDR -d 0
 Encode request successfully
 Request Message:
 08 01 80 02 51 00 00 00 00 00 00 00 00 01 80 00 00 00
 On first recv(),response == request : RC = 0
 Total length: 46
 Response Message:
 08 01 00 02 51 00 02 00 00 00 00 00 00 00 01 1d 00 01 00 00 00 01 0b 00 00 13 00 00 00 01 00 21 00 00 00 00 00 00 00 00 00 01 c4 00 01 06
 Parsed Response Msg:
 recordHandle: 1
 PDRHeaderVersion: 1
 PDRType: 11
 recordChangeNumber: 0
 dataLength: 19
 PLDMTerminusHandle: 0
 effecterID: 1
 entityType: 33
 entityInstanceNumber: 0
 containerID: 0
 effecterSemanticID: 0
 effecterInit: 0
 effecterDescriptionPDR: false
 compositeEffecterCount: 1
 stateSetID: 196
 possibleStatesSize: 1
 possibleStates: 6

 $ pldmtool platform SetStateEffecterStates -d 1 1 1
 Encode request successfully
 Request Message:
 08 01 80 02 39 01 00 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 On first recv(),response == request : RC = 0
 Total length: 6
 Response Message:
 08 01 00 02 39 00
 SetStateEffecterStates: SUCCESS

 $ pldmtool bios SetDateTime -d 20191010080000
 Encode request successfully
 Request Message:
 08 01 80 03 0d 00 00 08 10 10 19 20
 On first recv(),response == request : RC = 0
 Total length: 6
 Response Message:
 08 01 00 03 0d 00
 SetDateTime: SUCCESS

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: Ie13c7b05937ee3f150802d33c6e3434360c0b606
diff --git a/tool/meson.build b/tool/meson.build
index 95f746c..254585c 100644
--- a/tool/meson.build
+++ b/tool/meson.build
@@ -1,6 +1,7 @@
 sources = [
   'pldm_cmd_helper.cpp',
   'pldm_base_cmd.cpp',
+  'pldm_platform_cmd.cpp',
   'pldm_bios_cmd.cpp',
   'pldmtool.cpp'
 ]
diff --git a/tool/pldm_bios_cmd.cpp b/tool/pldm_bios_cmd.cpp
index 547955e..fdcc721 100644
--- a/tool/pldm_bios_cmd.cpp
+++ b/tool/pldm_bios_cmd.cpp
@@ -83,6 +83,74 @@
     }
 };
 
+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(
+            PLDM_LOCAL_INSTANCE_ID, 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;
+};
+
 void registerCommand(CLI::App& app)
 {
     auto bios = app.add_subcommand("bios", "bios type command");
@@ -90,6 +158,11 @@
     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));
 }
 
 } // namespace bios
diff --git a/tool/pldm_bios_cmd.hpp b/tool/pldm_bios_cmd.hpp
index 4448f7e..cb80b0f 100644
--- a/tool/pldm_bios_cmd.hpp
+++ b/tool/pldm_bios_cmd.hpp
@@ -1,5 +1,4 @@
 #pragma once
-
 #include <CLI/CLI.hpp>
 
 namespace pldmtool
@@ -9,6 +8,7 @@
 {
 
 void registerCommand(CLI::App& app);
-}
+
+} // namespace bios
 
 } // namespace pldmtool
diff --git a/tool/pldm_platform_cmd.cpp b/tool/pldm_platform_cmd.cpp
new file mode 100644
index 0000000..da6605d
--- /dev/null
+++ b/tool/pldm_platform_cmd.cpp
@@ -0,0 +1,252 @@
+#include "pldm_cmd_helper.hpp"
+
+#include <string>
+#include <vector>
+
+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(PLDM_LOCAL_INSTANCE_ID, 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[255] = {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, sizeof(recordData));
+    }
+
+  private:
+    void printPDR11(uint8_t* data, size_t len)
+    {
+        if (data == NULL || len == 0)
+        {
+            return;
+        }
+
+        struct pldm_state_effecter_pdr* pdr =
+            (struct pldm_state_effecter_pdr*)data;
+        std::cout << "recordHandle: " << pdr->hdr.record_handle << std::endl;
+        std::cout << "PDRHeaderVersion: " << unsigned(pdr->hdr.version)
+                  << std::endl;
+        std::cout << "PDRType: " << unsigned(pdr->hdr.type) << std::endl;
+        std::cout << "recordChangeNumber: " << pdr->hdr.record_change_num
+                  << std::endl;
+        std::cout << "dataLength: " << pdr->hdr.length << std::endl;
+        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, size_t len)
+    {
+        if (data == NULL || len == 0)
+        {
+            return;
+        }
+
+        std::cout << "Parsed Response Msg: " << std::endl;
+        std::cout << "nextRecordHandle: " << nextRecordHndl << std::endl;
+        std::cout << "responseCount: " << respCnt << std::endl;
+
+        struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
+        switch (pdr->type)
+        {
+            case PLDM_STATE_EFFECTER_PDR:
+                printPDR11(data, len);
+                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;
+
+    //  effecterID(1) +  compositeEffecterCount(value: 0x01 to 0x08) *
+    //  stateField(2)
+    static constexpr auto maxEffecterDataSize = 17;
+    explicit SetStateEffecter(const char* type, const char* name,
+                              CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option(
+               "-d,--data", effecterData,
+               "set effecter state data, the noChange value is 0 and the "
+               "requestSet value is 1 and access up to eight sets of state "
+               "effector information. \n"
+               "eg1: effecterID, requestSet0, effecterState0... \n"
+               "eg2: effecterID, noChange0, requestSet1, effecterState1...")
+            ->required()
+            ->expected(-1);
+    }
+
+    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 (effecterData.size() > maxEffecterDataSize)
+        {
+            std::cerr << "Request Message Error: effecterData size "
+                      << effecterData.size() << std::endl;
+            auto rc = PLDM_ERROR_INVALID_DATA;
+            return {rc, requestMsg};
+        }
+
+        uint16_t effecterId = 0;
+        std::vector<set_effecter_state_field> stateField = {};
+        if (!decodeEffecterData(effecterData, effecterId, stateField))
+        {
+            auto rc = PLDM_ERROR_INVALID_DATA;
+            return {rc, requestMsg};
+        }
+
+        auto rc = encode_set_state_effecter_states_req(
+            PLDM_LOCAL_INSTANCE_ID, effecterId, stateField.size(),
+            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
+                      << std::endl;
+            return;
+        }
+
+        std::cout << "SetStateEffecterStates: SUCCESS" << std::endl;
+    }
+
+  private:
+    std::vector<uint8_t> effecterData;
+};
+
+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));
+}
+
+} // namespace platform
+} // namespace pldmtool
diff --git a/tool/pldm_platform_cmd.hpp b/tool/pldm_platform_cmd.hpp
new file mode 100644
index 0000000..45f15ba
--- /dev/null
+++ b/tool/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/tool/pldmtool.cpp b/tool/pldmtool.cpp
index 059bd8e..0f0182b 100644
--- a/tool/pldmtool.cpp
+++ b/tool/pldmtool.cpp
@@ -1,6 +1,7 @@
 #include "pldm_base_cmd.hpp"
 #include "pldm_bios_cmd.hpp"
 #include "pldm_cmd_helper.hpp"
+#include "pldm_platform_cmd.hpp"
 
 #include <CLI/CLI.hpp>
 
@@ -68,6 +69,7 @@
     pldmtool::raw::registerCommand(app);
     pldmtool::base::registerCommand(app);
     pldmtool::bios::registerCommand(app);
+    pldmtool::platform::registerCommand(app);
 
     CLI11_PARSE(app, argc, argv);
     return 0;