Pldmtool change to fetch pdrs based on TerminusID

This commit adds a new option "-n" to getPDR in the pldmtool using
which we can retrieve the PDRs based on the terminus ID.

Tested:
 ./pldmtool platform getpdr -h
get platform descriptor records
Usage: ./pldmtool platform GetPDR [OPTIONS]

Options:
  -h,--help                   Print this help message and exit
  -m,--mctp_eid UINT          MCTP endpoint ID
  -v,--verbose
[Option Group: Required Option]
  Retrieve individual PDR, all PDRs, PDRs of a requested type or retrieve all PDRs of the requested terminusID
  [Exactly 1 of the following options is required]
  Options:
    -d,--data UINT              retrieve individual PDRs from a PDR Repository
                                eg: The recordHandle value for the PDR to be retrieved and 0 means get first PDR in the repository.
    -t,--type TEXT              retrieve all PDRs of the requested type
                                supported types:
                                [terminusLocator, stateSensor, numericEffecter, stateEffecter, EntityAssociation, fruRecord, ... ]
    -i,--terminusID UINT          retrieve all PDRs of the requested terminusID
                                supported IDs:
                                 [1, 2, 208...]
    -a,--all                    retrieve all PDRs from a PDR repository

Example 1:
./pldmtool platform getpdr -i 0
[]

Example 2:
./pldmtool platform getpdr -i 2
Copied the output here:
https://gist.github.com/Pavithrab7/4218104bc7e58951ff91fe5b49e562b0

Change-Id: I8b78818abbbbb3678e180d2bd1f38017454fd0d3
Signed-off-by: Pavithra Barithaya <pavithra.b@ibm.com>
diff --git a/pldmtool/pldm_cmd_helper.hpp b/pldmtool/pldm_cmd_helper.hpp
index 6f185dd..1f21ea2 100644
--- a/pldmtool/pldm_cmd_helper.hpp
+++ b/pldmtool/pldm_cmd_helper.hpp
@@ -109,6 +109,26 @@
         return mctp_eid;
     }
 
+    /**
+     * @brief get PLDM type
+     *
+     * @return pldm type
+     */
+    inline std::string getPLDMType()
+    {
+        return pldmType;
+    }
+
+    /**
+     * @brief get command name
+     *
+     * @return  the command name
+     */
+    inline std::string getCommandName()
+    {
+        return commandName;
+    }
+
   private:
     const std::string pldmType;
     const std::string commandName;
diff --git a/pldmtool/pldm_platform_cmd.cpp b/pldmtool/pldm_platform_cmd.cpp
index e141312..d8b1b15 100644
--- a/pldmtool/pldm_platform_cmd.cpp
+++ b/pldmtool/pldm_platform_cmd.cpp
@@ -67,7 +67,7 @@
     {
         auto pdrOptionGroup = app->add_option_group(
             "Required Option",
-            "Retrieve individual PDR, all PDRs, or PDRs of a requested type");
+            "Retrieve individual PDR, all PDRs, PDRs of a requested type or retrieve all PDRs of the requested terminusID");
         pdrOptionGroup->add_option(
             "-d,--data", recordHandle,
             "retrieve individual PDRs from a PDR Repository\n"
@@ -80,12 +80,59 @@
                                    "[terminusLocator, stateSensor, "
                                    "numericEffecter, stateEffecter, "
                                    "EntityAssociation, fruRecord, ... ]");
+
+        getPDRGroupOption = pdrOptionGroup->add_option(
+            "-i, --terminusID", pdrTerminus,
+            "retrieve all PDRs of the requested terminusID\n"
+            "supported IDs:\n [1, 2, 208...]");
+
         allPDRs = false;
         pdrOptionGroup->add_flag("-a, --all", allPDRs,
                                  "retrieve all PDRs from a PDR repository");
+
         pdrOptionGroup->require_option(1);
     }
 
+    void parseGetPDROptions()
+    {
+        optTIDSet = false;
+        if (getPDRGroupOption->count() > 0)
+        {
+            optTIDSet = true;
+            getPDRs();
+        }
+    }
+
+    void getPDRs()
+    {
+        // start the array
+        std::cout << "[";
+
+        recordHandle = 0;
+        do
+        {
+            CommandInterface::exec();
+        } while (recordHandle != 0);
+
+        // close the array
+        std::cout << "]\n";
+
+        if (handleFound)
+        {
+            recordHandle = 0;
+            uint32_t prevRecordHandle = 0;
+            do
+            {
+                CommandInterface::exec();
+                if (recordHandle == prevRecordHandle)
+                {
+                    return;
+                }
+                prevRecordHandle = recordHandle;
+            } while (recordHandle != 0);
+        }
+    }
+
     void exec() override
     {
         if (allPDRs || !pdrRecType.empty())
@@ -178,8 +225,26 @@
             return;
         }
 
-        printPDRMsg(nextRecordHndl, respCnt, recordData);
-        recordHandle = nextRecordHndl;
+        if (optTIDSet && !handleFound)
+        {
+            terminusHandle = getTerminusHandle(recordData, pdrTerminus);
+            if (terminusHandle.has_value())
+            {
+                recordHandle = 0;
+                return;
+            }
+            else
+            {
+                recordHandle = nextRecordHndl;
+                return;
+            }
+        }
+
+        else
+        {
+            printPDRMsg(nextRecordHndl, respCnt, recordData, terminusHandle);
+            recordHandle = nextRecordHndl;
+        }
     }
 
   private:
@@ -960,6 +1025,69 @@
         }
     }
 
+    bool checkTerminusHandle(const uint8_t* data,
+                             std::optional<uint16_t> terminusHandle)
+    {
+        struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
+
+        if (pdr->type == PLDM_TERMINUS_LOCATOR_PDR)
+        {
+            auto tlpdr =
+                reinterpret_cast<const pldm_terminus_locator_pdr*>(data);
+
+            if (tlpdr->terminus_handle != terminusHandle)
+            {
+                return true;
+            }
+        }
+        else if (pdr->type == PLDM_STATE_SENSOR_PDR)
+        {
+            auto sensor = reinterpret_cast<const pldm_state_sensor_pdr*>(data);
+
+            if (sensor->terminus_handle != terminusHandle)
+            {
+                return true;
+            }
+        }
+        else if (pdr->type == PLDM_NUMERIC_EFFECTER_PDR)
+        {
+            auto numericEffecter =
+                reinterpret_cast<const pldm_numeric_effecter_value_pdr*>(data);
+
+            if (numericEffecter->terminus_handle != terminusHandle)
+            {
+                return true;
+            }
+        }
+
+        else if (pdr->type == PLDM_STATE_EFFECTER_PDR)
+        {
+            auto stateEffecter =
+                reinterpret_cast<const pldm_state_effecter_pdr*>(data);
+            if (stateEffecter->terminus_handle != terminusHandle)
+            {
+                return true;
+            }
+        }
+        else if (pdr->type == PLDM_PDR_FRU_RECORD_SET)
+        {
+            data += sizeof(pldm_pdr_hdr);
+            auto fru = reinterpret_cast<const pldm_pdr_fru_record_set*>(data);
+
+            if (fru->terminus_handle != terminusHandle)
+            {
+                return true;
+            }
+        }
+        else
+        {
+            // Entity association PDRs does not have terminus handle
+            return true;
+        }
+
+        return false;
+    }
+
     void printTerminusLocatorPDR(const uint8_t* data, ordered_json& output)
     {
         const std::array<std::string_view, 4> terminusLocatorType = {
@@ -985,8 +1113,24 @@
         }
     }
 
+    std::optional<uint16_t> getTerminusHandle(uint8_t* data,
+                                              std::optional<uint8_t> tid)
+    {
+        struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
+        if (pdr->type == PLDM_TERMINUS_LOCATOR_PDR)
+        {
+            auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(data);
+            if (pdr->tid == tid)
+            {
+                handleFound = true;
+                return pdr->terminus_handle;
+            }
+        }
+        return std::nullopt;
+    }
+
     void printPDRMsg(uint32_t& nextRecordHndl, const uint16_t respCnt,
-                     uint8_t* data)
+                     uint8_t* data, std::optional<uint16_t> terminusHandle)
     {
         if (data == NULL)
         {
@@ -1026,6 +1170,16 @@
             }
         }
 
+        if (pdrTerminus.has_value())
+        {
+            if (checkTerminusHandle(data, terminusHandle))
+            {
+                std::cerr << "The Terminus handle doesn't match return"
+                          << std::endl;
+                return;
+            }
+        }
+
         printCommonPDRHeader(pdr, output);
 
         switch (pdr->type)
@@ -1055,9 +1209,14 @@
     }
 
   private:
+    bool optTIDSet = false;
     uint32_t recordHandle;
     bool allPDRs;
     std::string pdrRecType;
+    std::optional<uint8_t> pdrTerminus;
+    std::optional<uint16_t> terminusHandle;
+    bool handleFound = false;
+    CLI::Option* getPDRGroupOption = nullptr;
 };
 
 class SetStateEffecter : public CommandInterface
@@ -1356,5 +1515,18 @@
         "platform", "getStateSensorReadings", getStateSensorReadings));
 }
 
+void parseGetPDROption()
+{
+    for (const auto& command : commands)
+    {
+        if (command.get()->getPLDMType() == "platform" &&
+            command.get()->getCommandName() == "getPDR")
+        {
+            auto getPDR = dynamic_cast<GetPDR*>(command.get());
+            getPDR->parseGetPDROptions();
+        }
+    }
+}
+
 } // namespace platform
 } // namespace pldmtool
diff --git a/pldmtool/pldm_platform_cmd.hpp b/pldmtool/pldm_platform_cmd.hpp
index 45f15ba..5d548dc 100644
--- a/pldmtool/pldm_platform_cmd.hpp
+++ b/pldmtool/pldm_platform_cmd.hpp
@@ -10,6 +10,13 @@
 
 void registerCommand(CLI::App& app);
 
+/*@brief method to parse the command line option for
+   get PDR command.
+*/
+void parseGetPDROption();
+
+void getPDRs();
+
 } // namespace platform
 
 } // namespace pldmtool
diff --git a/pldmtool/pldmtool.cpp b/pldmtool/pldmtool.cpp
index cecc965..ff898d0 100644
--- a/pldmtool/pldmtool.cpp
+++ b/pldmtool/pldmtool.cpp
@@ -80,5 +80,6 @@
 #endif
 
     CLI11_PARSE(app, argc, argv);
+    pldmtool::platform::parseGetPDROption();
     return 0;
 }