pldmtool: support GetNextPart for GetPDR command

Current pldmtool assumes GetPDR command always have one PDR from each
response which causing incompleted PDR data if the devices have smaller
packet size limitation.

Add GetNextPart support for collecting a full PDR from multiple
commands.

Change-Id: Idf6805751e3870c65daf3e411c011b021992a912
Signed-off-by: Potin Lai <potin.lai@quantatw.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
diff --git a/pldmtool/pldm_platform_cmd.cpp b/pldmtool/pldm_platform_cmd.cpp
index 19f23fd..21d0c8a 100644
--- a/pldmtool/pldm_platform_cmd.cpp
+++ b/pldmtool/pldm_platform_cmd.cpp
@@ -66,7 +66,9 @@
     using CommandInterface::CommandInterface;
 
     explicit GetPDR(const char* type, const char* name, CLI::App* app) :
-        CommandInterface(type, name, app)
+        CommandInterface(type, name, app), dataTransferHandle(0),
+        operationFlag(PLDM_GET_FIRSTPART), requestCount(UINT16_MAX),
+        recordChangeNumber(0), nextPartRequired(false)
     {
         auto pdrOptionGroup = app->add_option_group(
             "Required Option",
@@ -161,7 +163,7 @@
                 // recordHandle is updated to nextRecord when
                 // CommandInterface::exec() is successful.
                 // In case of any error, return.
-                if (recordHandle == prevRecordHandle)
+                if (recordHandle == prevRecordHandle && !nextPartRequired)
                 {
                     return;
                 }
@@ -169,7 +171,7 @@
                 // check for circular references.
                 auto result = recordsSeen.emplace(recordHandle,
                                                   prevRecordHandle);
-                if (!result.second)
+                if (!result.second && !nextPartRequired)
                 {
                     std::cerr
                         << "Record handle " << recordHandle
@@ -191,7 +193,10 @@
         }
         else
         {
-            CommandInterface::exec();
+            do
+            {
+                CommandInterface::exec();
+            } while (nextPartRequired);
         }
     }
 
@@ -201,16 +206,16 @@
                                         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, UINT16_MAX, 0, request,
-                                     PLDM_GET_PDR_REQ_BYTES);
+        auto rc = encode_get_pdr_req(
+            instanceId, recordHandle, dataTransferHandle, operationFlag,
+            requestCount, recordChangeNumber, 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[UINT16_MAX] = {0};
+        uint8_t respRecordData[UINT16_MAX] = {0};
         uint32_t nextRecordHndl = 0;
         uint32_t nextDataTransferHndl = 0;
         uint8_t transferFlag = 0;
@@ -219,20 +224,21 @@
 
         auto rc = decode_get_pdr_resp(
             responsePtr, payloadLength, &completionCode, &nextRecordHndl,
-            &nextDataTransferHndl, &transferFlag, &respCnt, recordData,
-            sizeof(recordData), &transferCRC);
+            &nextDataTransferHndl, &transferFlag, &respCnt, respRecordData,
+            sizeof(respRecordData), &transferCRC);
 
         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
         {
             std::cerr << "Response Message Error: "
                       << "rc=" << rc << ",cc=" << (int)completionCode
                       << std::endl;
+            nextPartRequired = false;
             return;
         }
 
         if (optTIDSet && !handleFound)
         {
-            terminusHandle = getTerminusHandle(recordData, pdrTerminus);
+            terminusHandle = getTerminusHandle(respRecordData, pdrTerminus);
             if (terminusHandle.has_value())
             {
                 recordHandle = 0;
@@ -244,11 +250,33 @@
                 return;
             }
         }
-
         else
         {
-            printPDRMsg(nextRecordHndl, respCnt, recordData, terminusHandle);
-            recordHandle = nextRecordHndl;
+            recordData.insert(recordData.end(), respRecordData,
+                              respRecordData + respCnt);
+
+            // End or StartAndEnd
+            if (transferFlag == PLDM_PLATFORM_TRANSFER_END ||
+                transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END)
+            {
+                printPDRMsg(nextRecordHndl, respCnt, recordData.data(),
+                            terminusHandle);
+                nextPartRequired = false;
+                recordHandle = nextRecordHndl;
+                dataTransferHandle = 0;
+                recordChangeNumber = 0;
+                operationFlag = PLDM_GET_FIRSTPART;
+                recordData.clear();
+            }
+            else
+            {
+                nextPartRequired = true;
+                dataTransferHandle = nextDataTransferHndl;
+                struct pldm_pdr_hdr* pdr_hdr =
+                    reinterpret_cast<struct pldm_pdr_hdr*>(respRecordData);
+                recordChangeNumber = pdr_hdr->record_change_num;
+                operationFlag = PLDM_GET_NEXTPART;
+            }
         }
     }
 
@@ -1543,6 +1571,12 @@
     std::optional<uint16_t> terminusHandle;
     bool handleFound = false;
     CLI::Option* getPDRGroupOption = nullptr;
+    uint32_t dataTransferHandle;
+    uint8_t operationFlag;
+    uint16_t requestCount;
+    uint16_t recordChangeNumber;
+    std::vector<uint8_t> recordData;
+    bool nextPartRequired;
 };
 
 class SetStateEffecter : public CommandInterface