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/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);
+}