platform-mc: PDR handling

Get PDRs of new terminus if it supports GetPDR PLDM command. It doesn't
handle the event receiver related initialization steps, and either
doesn't support primary PDR repository to maintain terminus locator PDR
information yet.
Added parse PDR member functions to terminus class for parsing Numeric
sensor PDR and sensor auxiliary names PDR.
Added sensor auxiliary names PDR and numeric sensor PDR struct in
libpldm/platform.h

Signed-off-by: Gilbert Chen <gilbert.chen@arm.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I30a0cc594a3c08fc17f2dad861b5c5d41c80ebdd
diff --git a/platform-mc/platform_manager.cpp b/platform-mc/platform_manager.cpp
index e1d7f96..21e4bcf 100644
--- a/platform-mc/platform_manager.cpp
+++ b/platform-mc/platform_manager.cpp
@@ -4,6 +4,8 @@
 
 #include <phosphor-logging/lg2.hpp>
 
+#include <ranges>
+
 PHOSPHOR_LOG2_USING;
 
 namespace pldm
@@ -20,9 +22,248 @@
             continue;
         }
         terminus->initialized = true;
+
+        if (terminus->doesSupportCommand(PLDM_PLATFORM, PLDM_GET_PDR))
+        {
+            auto rc = co_await getPDRs(terminus);
+            if (rc)
+            {
+                lg2::error(
+                    "Failed to fetch PDRs for terminus with TID: {TID}, error: {ERROR}",
+                    "TID", tid, "ERROR", rc);
+                continue; // Continue to next terminus
+            }
+
+            terminus->parseTerminusPDRs();
+        }
     }
     co_return PLDM_SUCCESS;
 }
 
+exec::task<int> PlatformManager::getPDRs(std::shared_ptr<Terminus> terminus)
+{
+    pldm_tid_t tid = terminus->getTid();
+
+    /* Setting default values when getPDRRepositoryInfo fails or does not
+     * support */
+    uint8_t repositoryState = PLDM_AVAILABLE;
+    uint32_t recordCount = std::numeric_limits<uint32_t>::max();
+    uint32_t repositorySize = 0;
+    uint32_t largestRecordSize = std::numeric_limits<uint32_t>::max();
+    if (terminus->doesSupportCommand(PLDM_PLATFORM,
+                                     PLDM_GET_PDR_REPOSITORY_INFO))
+    {
+        auto rc = co_await getPDRRepositoryInfo(tid, repositoryState,
+                                                recordCount, repositorySize,
+                                                largestRecordSize);
+        if (rc)
+        {
+            lg2::error(
+                "Failed to get PDR Repository Info for terminus with TID: {TID}, error: {ERROR}",
+                "TID", tid, "ERROR", rc);
+        }
+        else
+        {
+            recordCount = std::min(recordCount + 1,
+                                   std::numeric_limits<uint32_t>::max());
+            largestRecordSize = std::min(largestRecordSize + 1,
+                                         std::numeric_limits<uint32_t>::max());
+        }
+    }
+
+    if (repositoryState != PLDM_AVAILABLE)
+    {
+        co_return PLDM_ERROR_NOT_READY;
+    }
+
+    uint32_t recordHndl = 0;
+    uint32_t nextRecordHndl = 0;
+    uint32_t nextDataTransferHndl = 0;
+    uint8_t transferFlag = 0;
+    uint16_t responseCnt = 0;
+    constexpr uint16_t recvBufSize = PLDM_PLATFORM_GETPDR_MAX_RECORD_BYTES;
+    std::vector<uint8_t> recvBuf(recvBufSize);
+    uint8_t transferCrc = 0;
+
+    terminus->pdrs.clear();
+    uint32_t receivedRecordCount = 0;
+
+    do
+    {
+        auto rc = co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART,
+                                  recvBufSize, 0, nextRecordHndl,
+                                  nextDataTransferHndl, transferFlag,
+                                  responseCnt, recvBuf, transferCrc);
+
+        if (rc)
+        {
+            lg2::error(
+                "Failed to get PDRs for terminus {TID}, error: {RC}, first part of record handle {RECORD}",
+                "TID", tid, "RC", rc, "RECORD", recordHndl);
+            terminus->pdrs.clear();
+            co_return rc;
+        }
+
+        if (transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END)
+        {
+            // single-part
+            terminus->pdrs.emplace_back(std::vector<uint8_t>(
+                recvBuf.begin(), recvBuf.begin() + responseCnt));
+            recordHndl = nextRecordHndl;
+        }
+        else
+        {
+            // multipart transfer
+            uint32_t receivedRecordSize = responseCnt;
+            auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(recvBuf.data());
+            uint16_t recordChgNum = le16toh(pdrHdr->record_change_num);
+            std::vector<uint8_t> receivedPdr(recvBuf.begin(),
+                                             recvBuf.begin() + responseCnt);
+            do
+            {
+                rc = co_await getPDR(tid, recordHndl, nextDataTransferHndl,
+                                     PLDM_GET_NEXTPART, recvBufSize,
+                                     recordChgNum, nextRecordHndl,
+                                     nextDataTransferHndl, transferFlag,
+                                     responseCnt, recvBuf, transferCrc);
+                if (rc)
+                {
+                    lg2::error(
+                        "Failed to get PDRs for terminus {TID}, error: {RC}, get middle part of record handle {RECORD}",
+                        "TID", tid, "RC", rc, "RECORD", recordHndl);
+                    terminus->pdrs.clear();
+                    co_return rc;
+                }
+
+                receivedPdr.insert(receivedPdr.end(), recvBuf.begin(),
+                                   recvBuf.begin() + responseCnt);
+                receivedRecordSize += responseCnt;
+
+                if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
+                {
+                    terminus->pdrs.emplace_back(std::move(receivedPdr));
+                    recordHndl = nextRecordHndl;
+                }
+            } while (nextDataTransferHndl != 0 &&
+                     receivedRecordSize < largestRecordSize);
+        }
+        receivedRecordCount++;
+    } while (nextRecordHndl != 0 && receivedRecordCount < recordCount);
+
+    co_return PLDM_SUCCESS;
+}
+
+exec::task<int> PlatformManager::getPDR(
+    const pldm_tid_t tid, const uint32_t recordHndl,
+    const uint32_t dataTransferHndl, const uint8_t transferOpFlag,
+    const uint16_t requestCnt, const uint16_t recordChgNum,
+    uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl,
+    uint8_t& transferFlag, uint16_t& responseCnt,
+    std::vector<uint8_t>& recordData, uint8_t& transferCrc)
+{
+    Request request(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES);
+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
+    auto rc = encode_get_pdr_req(0, recordHndl, dataTransferHndl,
+                                 transferOpFlag, requestCnt, recordChgNum,
+                                 requestMsg, PLDM_GET_PDR_REQ_BYTES);
+    if (rc)
+    {
+        lg2::error(
+            "Failed to encode request GetPDR for terminus ID {TID}, error {RC} ",
+            "TID", tid, "RC", rc);
+        co_return rc;
+    }
+
+    const pldm_msg* responseMsg = nullptr;
+    size_t responseLen = 0;
+    rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
+                                                  &responseLen);
+    if (rc)
+    {
+        lg2::error(
+            "Failed to send GetPDR message for terminus {TID}, error {RC}",
+            "TID", tid, "RC", rc);
+        co_return rc;
+    }
+
+    uint8_t completionCode;
+    rc = decode_get_pdr_resp(responseMsg, responseLen, &completionCode,
+                             &nextRecordHndl, &nextDataTransferHndl,
+                             &transferFlag, &responseCnt, recordData.data(),
+                             recordData.size(), &transferCrc);
+    if (rc)
+    {
+        lg2::error(
+            "Failed to decode response GetPDR for terminus ID {TID}, error {RC} ",
+            "TID", tid, "RC", rc);
+        co_return rc;
+    }
+
+    if (completionCode != PLDM_SUCCESS)
+    {
+        lg2::error("Error : GetPDR for terminus ID {TID}, complete code {CC}.",
+                   "TID", tid, "CC", completionCode);
+        co_return rc;
+    }
+
+    co_return completionCode;
+}
+
+exec::task<int> PlatformManager::getPDRRepositoryInfo(
+    const pldm_tid_t tid, uint8_t& repositoryState, uint32_t& recordCount,
+    uint32_t& repositorySize, uint32_t& largestRecordSize)
+{
+    Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t));
+    auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
+    auto rc = encode_pldm_header_only(PLDM_REQUEST, 0, PLDM_PLATFORM,
+                                      PLDM_GET_PDR_REPOSITORY_INFO, requestMsg);
+    if (rc)
+    {
+        lg2::error(
+            "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
+            "TID", tid, "RC", rc);
+        co_return rc;
+    }
+
+    const pldm_msg* responseMsg = nullptr;
+    size_t responseLen = 0;
+    rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
+                                                  &responseLen);
+    if (rc)
+    {
+        lg2::error(
+            "Failed to send GetPDRRepositoryInfo message for terminus {TID}, error {RC}",
+            "TID", tid, "RC", rc);
+        co_return rc;
+    }
+
+    uint8_t completionCode = 0;
+    std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> updateTime = {};
+    std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> oemUpdateTime = {};
+    uint8_t dataTransferHandleTimeout = 0;
+
+    rc = decode_get_pdr_repository_info_resp(
+        responseMsg, responseLen, &completionCode, &repositoryState,
+        updateTime.data(), oemUpdateTime.data(), &recordCount, &repositorySize,
+        &largestRecordSize, &dataTransferHandleTimeout);
+    if (rc)
+    {
+        lg2::error(
+            "Failed to decode response GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
+            "TID", tid, "RC", rc);
+        co_return rc;
+    }
+
+    if (completionCode != PLDM_SUCCESS)
+    {
+        lg2::error(
+            "Error : GetPDRRepositoryInfo for terminus ID {TID}, complete code {CC}.",
+            "TID", tid, "CC", completionCode);
+        co_return rc;
+    }
+
+    co_return completionCode;
+}
+
 } // namespace platform_mc
 } // namespace pldm
diff --git a/platform-mc/platform_manager.hpp b/platform-mc/platform_manager.hpp
index a7fd412..8187ca1 100644
--- a/platform-mc/platform_manager.hpp
+++ b/platform-mc/platform_manager.hpp
@@ -6,6 +6,8 @@
 #include "terminus.hpp"
 #include "terminus_manager.hpp"
 
+#include <vector>
+
 namespace pldm
 {
 
@@ -40,6 +42,53 @@
     exec::task<int> initTerminus();
 
   private:
+    /** @brief Fetch all PDRs from terminus.
+     *
+     *  @param[in] terminus - The terminus object to store fetched PDRs
+     *  @return coroutine return_value - PLDM completion code
+     */
+    exec::task<int> getPDRs(std::shared_ptr<Terminus> terminus);
+
+    /** @brief Fetch PDR from terminus
+     *
+     *  @param[in] tid - Destination TID
+     *  @param[in] recordHndl - Record handle
+     *  @param[in] dataTransferHndl - Data transfer handle
+     *  @param[in] transferOpFlag - Transfer Operation Flag
+     *  @param[in] requstCnt - Request Count of data
+     *  @param[in] recordChgNum - Record change number
+     *  @param[out] nextRecordHndl - Next record handle
+     *  @param[out] nextDataTransferHndl - Next data transfer handle
+     *  @param[out] transferFlag - Transfer flag
+     *  @param[out] responseCnt - Response count of record data
+     *  @param[out] recordData - Returned record data
+     *  @param[out] transferCrc - CRC value when record data is last part of PDR
+     *  @return coroutine return_value - PLDM completion code
+     */
+    exec::task<int>
+        getPDR(const pldm_tid_t tid, const uint32_t recordHndl,
+               const uint32_t dataTransferHndl, const uint8_t transferOpFlag,
+               const uint16_t requestCnt, const uint16_t recordChgNum,
+               uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl,
+               uint8_t& transferFlag, uint16_t& responseCnt,
+               std::vector<uint8_t>& recordData, uint8_t& transferCrc);
+
+    /** @brief get PDR repository information.
+     *
+     *  @param[in] tid - Destination TID
+     *  @param[out] repositoryState - the state of repository
+     *  @param[out] recordCount - number of records
+     *  @param[out] repositorySize - repository size
+     *  @param[out] largestRecordSize - largest record size
+     * *
+     *  @return coroutine return_value - PLDM completion code
+     */
+    exec::task<int> getPDRRepositoryInfo(const pldm_tid_t tid,
+                                         uint8_t& repositoryState,
+                                         uint32_t& recordCount,
+                                         uint32_t& repositorySize,
+                                         uint32_t& largestRecordSize);
+
     /** reference of TerminusManager for sending PLDM request to terminus*/
     TerminusManager& terminusManager;
 
diff --git a/platform-mc/terminus.cpp b/platform-mc/terminus.cpp
index 947571b..194583f 100644
--- a/platform-mc/terminus.cpp
+++ b/platform-mc/terminus.cpp
@@ -4,6 +4,8 @@
 
 #include "terminus_manager.hpp"
 
+#include <ranges>
+
 namespace pldm
 {
 namespace platform_mc
@@ -49,5 +51,243 @@
     return false;
 }
 
+void Terminus::parseTerminusPDRs()
+{
+    std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
+        numericSensorPdrs{};
+    std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
+        compactNumericSensorPdrs{};
+
+    for (auto& pdr : pdrs)
+    {
+        auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
+        switch (pdrHdr->type)
+        {
+            case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
+            {
+                auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
+                if (!sensorAuxNames)
+                {
+                    lg2::error(
+                        "Failed to parse PDR with type {TYPE} handle {HANDLE}",
+                        "TYPE", pdrHdr->type, "HANDLE",
+                        static_cast<uint32_t>(pdrHdr->record_handle));
+                    continue;
+                }
+                sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
+                break;
+            }
+            case PLDM_NUMERIC_SENSOR_PDR:
+            {
+                auto parsedPdr = parseNumericSensorPDR(pdr);
+                if (!parsedPdr)
+                {
+                    lg2::error(
+                        "Failed to parse PDR with type {TYPE} handle {HANDLE}",
+                        "TYPE", pdrHdr->type, "HANDLE",
+                        static_cast<uint32_t>(pdrHdr->record_handle));
+                    continue;
+                }
+                numericSensorPdrs.emplace_back(std::move(parsedPdr));
+                break;
+            }
+            case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
+            {
+                auto parsedPdr = parseCompactNumericSensorPDR(pdr);
+                if (!parsedPdr)
+                {
+                    lg2::error(
+                        "Failed to parse PDR with type {TYPE} handle {HANDLE}",
+                        "TYPE", pdrHdr->type, "HANDLE",
+                        static_cast<uint32_t>(pdrHdr->record_handle));
+                    continue;
+                }
+                auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
+                if (!sensorAuxNames)
+                {
+                    lg2::error(
+                        "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
+                        "TYPE", pdrHdr->type, "HANDLE",
+                        static_cast<uint32_t>(pdrHdr->record_handle));
+                    continue;
+                }
+                compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
+                sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
+                break;
+            }
+            default:
+            {
+                lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
+                           "TYPE", pdrHdr->type, "HANDLE",
+                           static_cast<uint32_t>(pdrHdr->record_handle));
+                break;
+            }
+        }
+    }
+}
+
+std::shared_ptr<SensorAuxiliaryNames>
+    Terminus::getSensorAuxiliaryNames(SensorId id)
+{
+    auto it = std::find_if(
+        sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
+        [id](
+            const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
+        const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
+        return sensorId == id;
+    });
+
+    if (it != sensorAuxiliaryNamesTbl.end())
+    {
+        return *it;
+    }
+    return nullptr;
+};
+
+std::shared_ptr<SensorAuxiliaryNames>
+    Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
+{
+    constexpr uint8_t nullTerminator = 0;
+    auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
+        pdrData.data());
+    const uint8_t* ptr = pdr->names;
+    std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
+        sensorAuxNames{};
+    char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
+    for ([[maybe_unused]] const auto& sensor :
+         std::views::iota(0, static_cast<int>(pdr->sensor_count)))
+    {
+        const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
+        ptr += sizeof(uint8_t);
+        std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
+        for ([[maybe_unused]] const auto& count :
+             std::views::iota(0, static_cast<int>(nameStringCount)))
+        {
+            std::string_view nameLanguageTag(
+                reinterpret_cast<const char*>(ptr));
+            ptr += nameLanguageTag.size() + sizeof(nullTerminator);
+
+            int u16NameStringLen = 0;
+            for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
+            {
+                u16NameStringLen++;
+            }
+            /* include terminator */
+            u16NameStringLen++;
+
+            std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
+            if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
+            {
+                lg2::error("Sensor name to long.");
+                return nullptr;
+            }
+            memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
+            std::u16string u16NameString(alignedBuffer, u16NameStringLen);
+            ptr += (u16NameString.size() + sizeof(nullTerminator)) *
+                   sizeof(uint16_t);
+            std::transform(u16NameString.cbegin(), u16NameString.cend(),
+                           u16NameString.begin(),
+                           [](uint16_t utf16) { return be16toh(utf16); });
+            std::string nameString =
+                std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
+                                     char16_t>{}
+                    .to_bytes(u16NameString);
+            std::replace(nameString.begin(), nameString.end(), ' ', '_');
+            auto nullTerminatorPos = nameString.find('\0');
+            if (nullTerminatorPos != std::string::npos)
+            {
+                nameString.erase(nullTerminatorPos);
+            }
+            nameStrings.emplace_back(
+                std::make_pair(nameLanguageTag, nameString));
+        }
+        sensorAuxNames.emplace_back(std::move(nameStrings));
+    }
+    return std::make_shared<SensorAuxiliaryNames>(
+        pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
+}
+
+std::shared_ptr<pldm_numeric_sensor_value_pdr>
+    Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
+{
+    const uint8_t* ptr = pdr.data();
+    auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
+    auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
+    if (rc)
+    {
+        return nullptr;
+    }
+    return parsedPdr;
+}
+
+std::shared_ptr<SensorAuxiliaryNames>
+    Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
+{
+    std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
+        sensorAuxNames{};
+    std::vector<std::pair<NameLanguageTag, SensorName>> nameStrings{};
+    auto pdr =
+        reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
+
+    if (sPdr.size() <
+        (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
+    {
+        return nullptr;
+    }
+
+    if (!pdr->sensor_name_length ||
+        (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
+                        sizeof(uint8_t) + pdr->sensor_name_length)))
+    {
+        return nullptr;
+    }
+
+    std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
+                           pdr->sensor_name_length);
+    std::replace(nameString.begin(), nameString.end(), ' ', '_');
+    auto nullTerminatorPos = nameString.find('\0');
+    if (nullTerminatorPos != std::string::npos)
+    {
+        nameString.erase(nullTerminatorPos);
+    }
+    nameStrings.emplace_back(std::make_pair("en", nameString));
+    sensorAuxNames.emplace_back(std::move(nameStrings));
+
+    return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
+                                                  std::move(sensorAuxNames));
+}
+
+std::shared_ptr<pldm_compact_numeric_sensor_pdr>
+    Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
+{
+    auto pdr =
+        reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
+    if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
+    {
+        // Handle error: input data too small to contain valid pdr
+        return nullptr;
+    }
+    auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
+
+    parsedPdr->hdr = pdr->hdr;
+    parsedPdr->terminus_handle = pdr->terminus_handle;
+    parsedPdr->sensor_id = pdr->sensor_id;
+    parsedPdr->entity_type = pdr->entity_type;
+    parsedPdr->entity_instance = pdr->entity_instance;
+    parsedPdr->container_id = pdr->container_id;
+    parsedPdr->sensor_name_length = pdr->sensor_name_length;
+    parsedPdr->base_unit = pdr->base_unit;
+    parsedPdr->unit_modifier = pdr->unit_modifier;
+    parsedPdr->occurrence_rate = pdr->occurrence_rate;
+    parsedPdr->range_field_support = pdr->range_field_support;
+    parsedPdr->warning_high = pdr->warning_high;
+    parsedPdr->warning_low = pdr->warning_low;
+    parsedPdr->critical_high = pdr->critical_high;
+    parsedPdr->critical_low = pdr->critical_low;
+    parsedPdr->fatal_high = pdr->fatal_high;
+    parsedPdr->fatal_low = pdr->fatal_low;
+    return parsedPdr;
+}
+
 } // namespace platform_mc
 } // namespace pldm
diff --git a/platform-mc/terminus.hpp b/platform-mc/terminus.hpp
index 6957fb3..3a1a302 100644
--- a/platform-mc/terminus.hpp
+++ b/platform-mc/terminus.hpp
@@ -11,6 +11,9 @@
 
 #include <algorithm>
 #include <bitset>
+#include <string>
+#include <tuple>
+#include <utility>
 #include <vector>
 
 namespace pldm
@@ -18,6 +21,14 @@
 namespace platform_mc
 {
 
+using SensorId = uint16_t;
+using SensorCnt = uint8_t;
+using NameLanguageTag = std::string;
+using SensorName = std::string;
+using SensorAuxiliaryNames = std::tuple<
+    SensorId, SensorCnt,
+    std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>>;
+
 /**
  * @brief Terminus
  *
@@ -68,6 +79,11 @@
 
         return true;
     }
+
+    /** @brief Parse the PDRs stored in the member variable, pdrs.
+     */
+    void parseTerminusPDRs();
+
     /** @brief The getter to return terminus's TID */
     pldm_tid_t getTid()
     {
@@ -80,7 +96,46 @@
     /** @brief A flag to indicate if terminus has been initialized */
     bool initialized = false;
 
+    /** @brief Get Sensor Auxiliary Names by sensorID
+     *
+     *  @param[in] id - sensor ID
+     *  @return sensor auxiliary names
+     */
+    std::shared_ptr<SensorAuxiliaryNames> getSensorAuxiliaryNames(SensorId id);
+
   private:
+    /** @brief Parse the numeric sensor PDRs
+     *
+     *  @param[in] pdrData - the response PDRs from GetPDR command
+     *  @return pointer to numeric sensor info struct
+     */
+    std::shared_ptr<pldm_numeric_sensor_value_pdr>
+        parseNumericSensorPDR(const std::vector<uint8_t>& pdrData);
+
+    /** @brief Parse the sensor Auxiliary name PDRs
+     *
+     *  @param[in] pdrData - the response PDRs from GetPDR command
+     *  @return pointer to sensor Auxiliary name info struct
+     */
+    std::shared_ptr<SensorAuxiliaryNames>
+        parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData);
+
+    /** @brief Parse the compact numeric sensor PDRs
+     *
+     *  @param[in] pdrData - the response PDRs from GetPDR command
+     *  @return pointer to compact numeric sensor info struct
+     */
+    std::shared_ptr<pldm_compact_numeric_sensor_pdr>
+        parseCompactNumericSensorPDR(const std::vector<uint8_t>& pdrData);
+
+    /** @brief Parse the sensor Auxiliary name from compact numeric sensor PDRs
+     *
+     *  @param[in] pdrData - the response PDRs from GetPDR command
+     *  @return pointer to sensor Auxiliary name info struct
+     */
+    std::shared_ptr<SensorAuxiliaryNames>
+        parseCompactNumericSensorNames(const std::vector<uint8_t>& pdrData);
+
     /* @brief The terminus's TID */
     pldm_tid_t tid;
 
@@ -96,6 +151,10 @@
      *         PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8).
      */
     std::vector<uint8_t> supportedCmds;
+
+    /* @brief Sensor Auxiliary Name list */
+    std::vector<std::shared_ptr<SensorAuxiliaryNames>>
+        sensorAuxiliaryNamesTbl{};
 };
 } // namespace platform_mc
 } // namespace pldm
diff --git a/platform-mc/test/meson.build b/platform-mc/test/meson.build
index f4e4f46..8c4f570 100644
--- a/platform-mc/test/meson.build
+++ b/platform-mc/test/meson.build
@@ -10,6 +10,7 @@
 tests = [
   'terminus_manager_test',
   'terminus_test',
+  'platform_manager_test',
 ]
 
 foreach t : tests
diff --git a/platform-mc/test/platform_manager_test.cpp b/platform-mc/test/platform_manager_test.cpp
new file mode 100644
index 0000000..2df2b48
--- /dev/null
+++ b/platform-mc/test/platform_manager_test.cpp
@@ -0,0 +1,316 @@
+#include "common/instance_id.hpp"
+#include "mock_terminus_manager.hpp"
+#include "platform-mc/platform_manager.hpp"
+#include "test/test_instance_id.hpp"
+
+#include <sdeventplus/event.hpp>
+
+#include <bitset>
+
+#include <gtest/gtest.h>
+
+class PlatformManagerTest : public testing::Test
+{
+  protected:
+    PlatformManagerTest() :
+        bus(pldm::utils::DBusHandler::getBus()),
+        event(sdeventplus::Event::get_default()), instanceIdDb(),
+        reqHandler(pldmTransport, event, instanceIdDb, false,
+                   std::chrono::seconds(1), 2, std::chrono::milliseconds(100)),
+        mockTerminusManager(event, reqHandler, instanceIdDb, termini, nullptr),
+        platformManager(mockTerminusManager, termini)
+    {}
+
+    PldmTransport* pldmTransport = nullptr;
+    sdbusplus::bus_t& bus;
+    sdeventplus::Event event;
+    TestInstanceIdDb instanceIdDb;
+    pldm::requester::Handler<pldm::requester::Request> reqHandler;
+    pldm::platform_mc::MockTerminusManager mockTerminusManager;
+    pldm::platform_mc::PlatformManager platformManager;
+    std::map<pldm_tid_t, std::shared_ptr<pldm::platform_mc::Terminus>> termini;
+};
+
+TEST_F(PlatformManagerTest, initTerminusTest)
+{
+    // Add terminus
+    auto mappedTid = mockTerminusManager.mapTid(pldm::MctpInfo(10, "", "", 1));
+    auto tid = mappedTid.value();
+    termini[tid] = std::make_shared<pldm::platform_mc::Terminus>(
+        tid, 1 << PLDM_BASE | 1 << PLDM_PLATFORM);
+    auto terminus = termini[tid];
+
+    /* Set supported command by terminus */
+    auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
+    std::vector<uint8_t> pldmCmds(size);
+    uint8_t type = PLDM_PLATFORM;
+    uint8_t cmd = PLDM_GET_PDR;
+    auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (cmd / 8);
+    pldmCmds[idx] = pldmCmds[idx] | (1 << (cmd % 8));
+    cmd = PLDM_GET_PDR_REPOSITORY_INFO;
+    idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (cmd / 8);
+    pldmCmds[idx] = pldmCmds[idx] | (1 << (cmd % 8));
+    termini[tid]->setSupportedCommands(pldmCmds);
+
+    // queue getPDRRepositoryInfo response
+    const size_t getPDRRepositoryInfoLen =
+        PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + getPDRRepositoryInfoLen>
+        getPDRRepositoryInfoResp{
+            0x0, 0x02, 0x50, PLDM_SUCCESS,
+            0x0,                                     // repositoryState
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, 0x0,
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, // updateTime
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, 0x0,
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, // OEMUpdateTime
+            1,   0x0,  0x0,  0x0,                    // recordCount
+            0x0, 0x1,  0x0,  0x0,                    // repositorySize
+            59,  0x0,  0x0,  0x0,                    // largestRecordSize
+            0x0 // dataTransferHandleTimeout
+        };
+    auto rc = mockTerminusManager.enqueueResponse(
+        (pldm_msg*)getPDRRepositoryInfoResp.data(),
+        sizeof(getPDRRepositoryInfoResp));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    // queue getPDR responses
+    const size_t getPdrRespLen = 81;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + getPdrRespLen> getPdrResp{
+        0x0, 0x02, 0x51, PLDM_SUCCESS, 0x0, 0x0, 0x0, 0x0, // nextRecordHandle
+        0x0, 0x0, 0x0, 0x0, // nextDataTransferHandle
+        0x5,                // transferFlag
+        69, 0x0,            // responseCount
+        // numeric Sensor PDR
+        0x1, 0x0, 0x0,
+        0x0,                     // record handle
+        0x1,                     // PDRHeaderVersion
+        PLDM_NUMERIC_SENSOR_PDR, // PDRType
+        0x0,
+        0x0,                     // recordChangeNumber
+        PLDM_PDR_NUMERIC_SENSOR_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_SENSOR_DATA_SIZE_MIN_LENGTH +
+            PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_RANGE_FIELD_MIN_LENGTH,
+        0,                             // dataLength
+        0,
+        0,                             // PLDMTerminusHandle
+        0x1,
+        0x0,                           // sensorID=1
+        120,
+        0,                             // entityType=Power Supply(120)
+        1,
+        0,                             // entityInstanceNumber
+        0x1,
+        0x0,                           // containerID=1
+        PLDM_NO_INIT,                  // sensorInit
+        false,                         // sensorAuxiliaryNamesPDR
+        PLDM_SENSOR_UNIT_DEGRESS_C,    // baseUint(2)=degrees C
+        1,                             // unitModifier = 1
+        0,                             // rateUnit
+        0,                             // baseOEMUnitHandle
+        0,                             // auxUnit
+        0,                             // auxUnitModifier
+        0,                             // auxRateUnit
+        0,                             // rel
+        0,                             // auxOEMUnitHandle
+        true,                          // isLinear
+        PLDM_SENSOR_DATA_SIZE_UINT8,   // sensorDataSize
+        0, 0, 0xc0,
+        0x3f,                          // resolution=1.5
+        0, 0, 0x80,
+        0x3f,                          // offset=1.0
+        0,
+        0,                             // accuracy
+        0,                             // plusTolerance
+        0,                             // minusTolerance
+        2,                             // hysteresis
+        0,                             // supportedThresholds
+        0,                             // thresholdAndHysteresisVolatility
+        0, 0, 0x80,
+        0x3f,                          // stateTransistionInterval=1.0
+        0, 0, 0x80,
+        0x3f,                          // updateInverval=1.0
+        255,                           // maxReadable
+        0,                             // minReadable
+        PLDM_RANGE_FIELD_FORMAT_UINT8, // rangeFieldFormat
+        0,                             // rangeFieldsupport
+        0,                             // nominalValue
+        0,                             // normalMax
+        0,                             // normalMin
+        0,                             // warningHigh
+        0,                             // warningLow
+        0,                             // criticalHigh
+        0,                             // criticalLow
+        0,                             // fatalHigh
+        0                              // fatalLow
+    };
+    rc = mockTerminusManager.enqueueResponse((pldm_msg*)getPdrResp.data(),
+                                             sizeof(getPdrResp));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    stdexec::sync_wait(platformManager.initTerminus());
+    EXPECT_EQ(true, terminus->initialized);
+    EXPECT_EQ(1, terminus->pdrs.size());
+}
+
+TEST_F(PlatformManagerTest, initTerminusDontSupportGetPDRTest)
+{
+    // Add terminus
+    auto mappedTid = mockTerminusManager.mapTid(pldm::MctpInfo(10, "", "", 1));
+    auto tid = mappedTid.value();
+    termini[tid] = std::make_shared<pldm::platform_mc::Terminus>(
+        tid, 1 << PLDM_BASE | 1 << PLDM_PLATFORM);
+    auto terminus = termini[tid];
+
+    /* Set supported command by terminus */
+    auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
+    std::vector<uint8_t> pldmCmds(size);
+    uint8_t type = PLDM_PLATFORM;
+    uint8_t cmd = PLDM_GET_PDR_REPOSITORY_INFO;
+    auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (cmd / 8);
+    pldmCmds[idx] = pldmCmds[idx] | (1 << (cmd % 8));
+    termini[tid]->setSupportedCommands(pldmCmds);
+
+    // queue getPDRRepositoryInfo response
+    const size_t getPDRRepositoryInfoLen =
+        PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + getPDRRepositoryInfoLen>
+        getPDRRepositoryInfoResp{
+            0x0, 0x02, 0x50, PLDM_SUCCESS,
+            0x0,                                     // repositoryState
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, 0x0,
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, // updateTime
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, 0x0,
+            0x0, 0x0,  0x0,  0x0,          0x0, 0x0, // OEMUpdateTime
+            1,   0x0,  0x0,  0x0,                    // recordCount
+            0x0, 0x1,  0x0,  0x0,                    // repositorySize
+            59,  0x0,  0x0,  0x0,                    // largestRecordSize
+            0x0 // dataTransferHandleTimeout
+        };
+    auto rc = mockTerminusManager.enqueueResponse(
+        (pldm_msg*)getPDRRepositoryInfoResp.data(),
+        sizeof(getPDRRepositoryInfoResp));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    // queue getPDR responses
+    const size_t getPdrRespLen = 81;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + getPdrRespLen> getPdrResp{
+        0x0, 0x02, 0x51, PLDM_SUCCESS, 0x0, 0x0, 0x0, 0x0, // nextRecordHandle
+        0x0, 0x0, 0x0, 0x0, // nextDataTransferHandle
+        0x5,                // transferFlag
+        69, 0x0,            // responseCount
+        // numeric Sensor PDR
+        0x1, 0x0, 0x0,
+        0x0,                     // record handle
+        0x1,                     // PDRHeaderVersion
+        PLDM_NUMERIC_SENSOR_PDR, // PDRType
+        0x0,
+        0x0,                     // recordChangeNumber
+        PLDM_PDR_NUMERIC_SENSOR_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_SENSOR_DATA_SIZE_MIN_LENGTH +
+            PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_RANGE_FIELD_MIN_LENGTH,
+        0,                             // dataLength
+        0,
+        0,                             // PLDMTerminusHandle
+        0x1,
+        0x0,                           // sensorID=1
+        120,
+        0,                             // entityType=Power Supply(120)
+        1,
+        0,                             // entityInstanceNumber
+        0x1,
+        0x0,                           // containerID=1
+        PLDM_NO_INIT,                  // sensorInit
+        false,                         // sensorAuxiliaryNamesPDR
+        PLDM_SENSOR_UNIT_DEGRESS_C,    // baseUint(2)=degrees C
+        1,                             // unitModifier = 1
+        0,                             // rateUnit
+        0,                             // baseOEMUnitHandle
+        0,                             // auxUnit
+        0,                             // auxUnitModifier
+        0,                             // auxRateUnit
+        0,                             // rel
+        0,                             // auxOEMUnitHandle
+        true,                          // isLinear
+        PLDM_SENSOR_DATA_SIZE_UINT8,   // sensorDataSize
+        0, 0, 0xc0,
+        0x3f,                          // resolution=1.5
+        0, 0, 0x80,
+        0x3f,                          // offset=1.0
+        0,
+        0,                             // accuracy
+        0,                             // plusTolerance
+        0,                             // minusTolerance
+        2,                             // hysteresis
+        0,                             // supportedThresholds
+        0,                             // thresholdAndHysteresisVolatility
+        0, 0, 0x80,
+        0x3f,                          // stateTransistionInterval=1.0
+        0, 0, 0x80,
+        0x3f,                          // updateInverval=1.0
+        255,                           // maxReadable
+        0,                             // minReadable
+        PLDM_RANGE_FIELD_FORMAT_UINT8, // rangeFieldFormat
+        0,                             // rangeFieldsupport
+        0,                             // nominalValue
+        0,                             // normalMax
+        0,                             // normalMin
+        0,                             // warningHigh
+        0,                             // warningLow
+        0,                             // criticalHigh
+        0,                             // criticalLow
+        0,                             // fatalHigh
+        0                              // fatalLow
+    };
+    rc = mockTerminusManager.enqueueResponse((pldm_msg*)getPdrResp.data(),
+                                             sizeof(getPdrResp));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    stdexec::sync_wait(platformManager.initTerminus());
+    EXPECT_EQ(true, terminus->initialized);
+    EXPECT_EQ(0, terminus->pdrs.size());
+}
+
+TEST_F(PlatformManagerTest, negativeInitTerminusTest1)
+{
+    // terminus doesn't Type2 support
+    auto mappedTid = mockTerminusManager.mapTid(pldm::MctpInfo(10, "", "", 1));
+    auto tid = mappedTid.value();
+    termini[tid] =
+        std::make_shared<pldm::platform_mc::Terminus>(tid, 1 << PLDM_BASE);
+    auto terminus = termini[tid];
+
+    stdexec::sync_wait(platformManager.initTerminus());
+    EXPECT_EQ(true, terminus->initialized);
+    EXPECT_EQ(0, terminus->pdrs.size());
+}
+
+TEST_F(PlatformManagerTest, negativeInitTerminusTest2)
+{
+    // terminus responses error
+    auto mappedTid = mockTerminusManager.mapTid(pldm::MctpInfo(10, "", "", 1));
+    auto tid = mappedTid.value();
+    termini[tid] = std::make_shared<pldm::platform_mc::Terminus>(
+        tid, 1 << PLDM_BASE | 1 << PLDM_PLATFORM);
+    auto terminus = termini[tid];
+
+    // queue getPDRRepositoryInfo response cc=PLDM_ERROR
+    const size_t getPDRRepositoryInfoLen = 1;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + getPDRRepositoryInfoLen>
+        getPDRRepositoryInfoResp{0x0, 0x02, 0x50, PLDM_ERROR};
+    auto rc = mockTerminusManager.enqueueResponse(
+        (pldm_msg*)getPDRRepositoryInfoResp.data(),
+        sizeof(getPDRRepositoryInfoResp));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    // queue getPDR responses cc=PLDM_ERROR
+    const size_t getPdrRespLen = 1;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + getPdrRespLen> getPdrResp{
+        0x0, 0x02, 0x51, PLDM_ERROR};
+    rc = mockTerminusManager.enqueueResponse((pldm_msg*)getPdrResp.data(),
+                                             sizeof(getPdrResp));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    stdexec::sync_wait(platformManager.initTerminus());
+    EXPECT_EQ(true, terminus->initialized);
+    EXPECT_EQ(0, terminus->pdrs.size());
+}
diff --git a/platform-mc/test/terminus_test.cpp b/platform-mc/test/terminus_test.cpp
index 32fd7b7..8919b19 100644
--- a/platform-mc/test/terminus_test.cpp
+++ b/platform-mc/test/terminus_test.cpp
@@ -1,3 +1,5 @@
+#include "libpldm/entity.h"
+
 #include "platform-mc/terminus.hpp"
 
 #include <gtest/gtest.h>
@@ -21,3 +23,59 @@
 
     EXPECT_EQ(tid, t1.getTid());
 }
+
+TEST(TerminusTest, parseSensorAuxiliaryNamesPDRTest)
+{
+    auto t1 = pldm::platform_mc::Terminus(1,
+                                          1 << PLDM_BASE | 1 << PLDM_PLATFORM);
+    std::vector<uint8_t> pdr1{
+        0x0,
+        0x0,
+        0x0,
+        0x1,                             // record handle
+        0x1,                             // PDRHeaderVersion
+        PLDM_SENSOR_AUXILIARY_NAMES_PDR, // PDRType
+        0x0,
+        0x0,                             // recordChangeNumber
+        0x0,
+        21,                              // dataLength
+        0,
+        0x0,                             // PLDMTerminusHandle
+        0x1,
+        0x0,                             // sensorID
+        0x1,                             // sensorCount
+        0x1,                             // nameStringCount
+        'e',
+        'n',
+        0x0, // nameLanguageTag
+        0x0,
+        'T',
+        0x0,
+        'E',
+        0x0,
+        'M',
+        0x0,
+        'P',
+        0x0,
+        '1',
+        0x0,
+        0x0 // sensorName
+    };
+
+    t1.pdrs.emplace_back(pdr1);
+    t1.parseTerminusPDRs();
+
+    auto sensorAuxNames = t1.getSensorAuxiliaryNames(0);
+    EXPECT_EQ(nullptr, sensorAuxNames);
+
+    sensorAuxNames = t1.getSensorAuxiliaryNames(1);
+    EXPECT_NE(nullptr, sensorAuxNames);
+
+    const auto& [sensorId, sensorCnt, names] = *sensorAuxNames;
+    EXPECT_EQ(1, sensorId);
+    EXPECT_EQ(1, sensorCnt);
+    EXPECT_EQ(1, names.size());
+    EXPECT_EQ(1, names[0].size());
+    EXPECT_EQ("en", names[0][0].first);
+    EXPECT_EQ("TEMP1", names[0][0].second);
+}