pdr: Update D-Bus mapping structure

For most PDR types, the D-Bus object structure(paths, interfaces, and
properties) should be defined in the JSON file instead of hard-coded.

Tested with JSON files:
 https://gist.github.com/lxwinspur/2c3fd68cdb35e06480c4a5f7890e3a06#file-effecter_pdr-json.

     pldmtool platform GetPDR -d 1
     Encode request successfully
     Request Message:
     08 01 80 02 51 01 00 00 00 00 00 00 00 01 80 00 00 00
     Success in creating the socket : RC = 3
     Success in connecting to socket : RC = 0
     Success in sending message type as pldm to mctp : RC = 0
     Write to socket successful : RC = 18
     Total length:18
     Loopback response message:
     08 01 80 02 51 01 00 00 00 00 00 00 00 01 80 00 00 00
     On first recv(),response == request : RC = 0
     Total length: 46
     Shutdown Socket successful :  RC = 0
     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:
     nextRecordHandle: 2
     responseCount: 29
     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

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: Ifc0cd1540b08e9b73e03d99d71a0980ef6353e72
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 8c9e45c..9c8860e 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -21,8 +21,13 @@
 namespace platform
 {
 
-using DbusPath = std::string;
-using EffecterObjs = std::vector<DbusPath>;
+using namespace pldm::utils;
+using namespace pldm::responder::pdr_utils;
+
+using EffecterId = uint16_t;
+using DbusMappings = std::vector<DBusMapping>;
+using DbusValMaps = std::vector<StatestoDbusVal>;
+using DbusObjMaps = std::map<EffecterId, std::tuple<DbusMappings, DbusValMaps>>;
 
 class Handler : public CmdHandler
 {
@@ -42,15 +47,31 @@
                          });
     }
 
-    const EffecterObjs& getEffecterObjs(uint16_t effecterId) const
+    pdr_utils::Repo& getRepo()
     {
-        return effecterObjs.at(effecterId);
+        return this->pdrRepo;
     }
 
-    void addEffecterObjs(uint16_t effecterId, EffecterObjs&& paths)
-    {
-        effecterObjs.emplace(effecterId, std::move(paths));
-    }
+    /** @brief Add D-Bus mapping and value mapping(stateId to D-Bus) for the
+     *         effecterId. If the same id is added, the previous dbusObjs will
+     *         be "over-written".
+     *
+     *  @param[in] effecterId - effecter id
+     *  @param[in] dbusObj - list of D-Bus object structure and list of D-Bus
+     *                       property value to attribute value
+     */
+    void addDbusObjMaps(uint16_t effecterId,
+                        std::tuple<DbusMappings, DbusValMaps> dbusObj);
+
+    /** @brief Retrieve an effecter id -> D-Bus objects mapping
+     *
+     *  @param[in] effecterId - effecter id
+     *
+     *  @return std::tuple<DbusMappings, DbusValMaps> - list of D-Bus object
+     *          structure and list of D-Bus property value to attribute value
+     */
+    const std::tuple<DbusMappings, DbusValMaps>&
+        getDbusObjMaps(uint16_t effecterId) const;
 
     uint16_t getNextEffecterId()
     {
@@ -103,37 +124,32 @@
     {
         using namespace pldm::responder::pdr;
         using namespace pldm::utils;
-        using namespace std::string_literals;
-        using DBusProperty = std::variant<std::string, bool>;
-        using StateSetId = uint16_t;
         using StateSetNum = uint8_t;
-        using PropertyMap =
-            std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
-        static const PropertyMap stateNumToDbusProp = {
-            {PLDM_BOOT_PROGRESS_STATE,
-             {{PLDM_BOOT_NOT_ACTIVE,
-               "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
-               "Standby"s},
-              {PLDM_BOOT_COMPLETED,
-               "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
-               "BootComplete"s}}},
-            {PLDM_SYSTEM_POWER_STATE,
-             {{PLDM_OFF_SOFT_GRACEFUL,
-               "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
-        using namespace pldm::responder::pdr;
 
         state_effecter_possible_states* states = nullptr;
         pldm_state_effecter_pdr* pdr = nullptr;
         uint8_t compEffecterCnt = stateField.size();
+
+        std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)>
+            stateEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy);
+        Repo stateEffecterPDRs(stateEffecterPdrRepo.get());
+        getRepoByType(pdrRepo, stateEffecterPDRs, PLDM_STATE_EFFECTER_PDR);
+        if (stateEffecterPDRs.empty())
+        {
+            std::cerr << "Failed to get record by PDR type\n";
+            return PLDM_PLATFORM_INVALID_EFFECTER_ID;
+        }
+
         PdrEntry pdrEntry{};
-        auto pdrRecord = pdrRepo.getFirstRecord(pdrEntry);
+        auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry);
         while (pdrRecord)
         {
             pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data);
             if (pdr->effecter_id != effecterId)
             {
                 pdr = nullptr;
-                pdrRecord = pdrRepo.getNextRecord(pdrRecord, pdrEntry);
+                pdrRecord =
+                    stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
                 continue;
             }
 
@@ -155,152 +171,77 @@
             return PLDM_PLATFORM_INVALID_EFFECTER_ID;
         }
 
-        std::map<StateSetId, std::function<int(const std::string& objPath,
-                                               const uint8_t currState)>>
-            effecterToDbusEntries = {
-                {PLDM_BOOT_PROGRESS_STATE,
-                 [&](const std::string& objPath, const uint8_t currState) {
-                     auto stateSet =
-                         stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
-                     if (stateSet == stateNumToDbusProp.end())
-                     {
-                         std::cerr << "Couldn't find D-Bus mapping for "
-                                   << "PLDM_BOOT_PROGRESS_STATE, EFFECTER_ID="
-                                   << effecterId << "\n";
-                         return PLDM_ERROR;
-                     }
-                     auto iter = stateSet->second.find(
-                         stateField[currState].effecter_state);
-                     if (iter == stateSet->second.end())
-                     {
-                         std::cerr << "Invalid state field passed or field not "
-                                   << "found for PLDM_BOOT_PROGRESS_STATE, "
-                                      "EFFECTER_ID="
-                                   << effecterId << " FIELD="
-                                   << stateField[currState].effecter_state
-                                   << " OBJECT_PATH=" << objPath.c_str()
-                                   << "\n";
-                         return PLDM_ERROR_INVALID_DATA;
-                     }
-                     PropertyValue value{std::get<std::string>(iter->second)};
-                     DBusMapping dbusMapping{
-                         objPath,
-                         "xyz.openbmc_project.State.OperatingSystem.Status",
-                         "OperatingSystemState", "string"};
-                     try
-                     {
-                         dBusIntf.setDbusProperty(dbusMapping, value);
-                     }
-                     catch (const std::exception& e)
-                     {
-                         std::cerr
-                             << "Error setting property, ERROR=" << e.what()
-                             << " PROPERTY=" << dbusMapping.propertyName
-                             << " INTERFACE="
-                             << dbusMapping.interface << " PATH="
-                             << dbusMapping.objectPath << "\n";
-                         return PLDM_ERROR;
-                     }
-                     return PLDM_SUCCESS;
-                 }},
-                {PLDM_SYSTEM_POWER_STATE,
-                 [&](const std::string& objPath, const uint8_t currState) {
-                     auto stateSet =
-                         stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
-                     if (stateSet == stateNumToDbusProp.end())
-                     {
-                         std::cerr << "Couldn't find D-Bus mapping for "
-                                   << "PLDM_SYSTEM_POWER_STATE, EFFECTER_ID="
-                                   << effecterId << "\n";
-                         return PLDM_ERROR;
-                     }
-                     auto iter = stateSet->second.find(
-                         stateField[currState].effecter_state);
-                     if (iter == stateSet->second.end())
-                     {
-                         std::cerr << "Invalid state field passed or field not "
-                                   << "found for PLDM_SYSTEM_POWER_STATE, "
-                                      "EFFECTER_ID="
-                                   << effecterId << " FIELD="
-                                   << stateField[currState].effecter_state
-                                   << " OBJECT_PATH=" << objPath.c_str()
-                                   << "\n";
-                         return PLDM_ERROR_INVALID_DATA;
-                     }
-                     PropertyValue value{std::get<std::string>(iter->second)};
-                     DBusMapping dbusMapping{
-                         objPath, "xyz.openbmc_project.State.Chassis",
-                         "RequestedPowerTransition", "string"};
-                     try
-                     {
-                         dBusIntf.setDbusProperty(dbusMapping, value);
-                     }
-                     catch (const std::exception& e)
-                     {
-                         std::cerr
-                             << "Error setting property, ERROR=" << e.what()
-                             << " PROPERTY=" << dbusMapping.propertyName
-                             << " INTERFACE="
-                             << dbusMapping.interface << " PATH="
-                             << dbusMapping.objectPath << "\n";
-                         return PLDM_ERROR;
-                     }
-                     return PLDM_SUCCESS;
-                 }}};
-
         int rc = PLDM_SUCCESS;
-        const auto& paths = getEffecterObjs(effecterId);
-        for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
+        try
         {
-            std::vector<StateSetNum> allowed{};
-            // computation is based on table 79 from DSP0248 v1.1.1
-            uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
-            uint8_t bit =
-                stateField[currState].effecter_state - (8 * bitfieldIndex);
-            if (states->possible_states_size < bitfieldIndex ||
-                !(states->states[bitfieldIndex].byte & (1 << bit)))
+            const auto& [dbusMappings, dbusValMaps] =
+                dbusObjMaps.at(effecterId);
+            for (uint8_t currState = 0; currState < compEffecterCnt;
+                 ++currState)
             {
-                std::cerr << "Invalid state set value, EFFECTER_ID="
-                          << effecterId
-                          << " VALUE=" << stateField[currState].effecter_state
-                          << " COMPOSITE_EFFECTER_ID=" << currState
-                          << " DBUS_PATH=" << paths[currState].c_str() << "\n";
-                rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
-                break;
-            }
-            auto iter = effecterToDbusEntries.find(states->state_set_id);
-            if (iter == effecterToDbusEntries.end())
-            {
-                uint16_t setId = states->state_set_id;
-                std::cerr << "Did not find the state set for the"
-                          << " state effecter pdr, STATE=" << setId
-                          << " EFFECTER_ID=" << effecterId << "\n";
-                rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
-                break;
-            }
-            if (stateField[currState].set_request == PLDM_REQUEST_SET)
-            {
-                rc = iter->second(paths[currState], currState);
-                if (rc != PLDM_SUCCESS)
+                std::vector<StateSetNum> allowed{};
+                // computation is based on table 79 from DSP0248 v1.1.1
+                uint8_t bitfieldIndex =
+                    stateField[currState].effecter_state / 8;
+                uint8_t bit =
+                    stateField[currState].effecter_state - (8 * bitfieldIndex);
+                if (states->possible_states_size < bitfieldIndex ||
+                    !(states->states[bitfieldIndex].byte & (1 << bit)))
                 {
+                    std::cerr
+                        << "Invalid state set value, EFFECTER_ID=" << effecterId
+                        << " VALUE=" << stateField[currState].effecter_state
+                        << " COMPOSITE_EFFECTER_ID=" << currState
+                        << " DBUS_PATH=" << dbusMappings[currState].objectPath
+                        << "\n";
+                    rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
                     break;
                 }
+                const DBusMapping& dbusMapping = dbusMappings[currState];
+                const StatestoDbusVal& dbusValToMap = dbusValMaps[currState];
+
+                if (stateField[currState].set_request == PLDM_REQUEST_SET)
+                {
+                    try
+                    {
+                        dBusIntf.setDbusProperty(
+                            dbusMapping,
+                            dbusValToMap.at(
+                                stateField[currState].effecter_state));
+                    }
+                    catch (const std::exception& e)
+                    {
+                        std::cerr
+                            << "Error setting property, ERROR=" << e.what()
+                            << " PROPERTY=" << dbusMapping.propertyName
+                            << " INTERFACE="
+                            << dbusMapping.interface << " PATH="
+                            << dbusMapping.objectPath << "\n";
+                        return PLDM_ERROR;
+                    }
+                }
+                uint8_t* nextState =
+                    reinterpret_cast<uint8_t*>(states) +
+                    sizeof(state_effecter_possible_states) -
+                    sizeof(states->states) +
+                    (states->possible_states_size * sizeof(states->states));
+                states = reinterpret_cast<state_effecter_possible_states*>(
+                    nextState);
             }
-            uint8_t* nextState =
-                reinterpret_cast<uint8_t*>(states) +
-                sizeof(state_effecter_possible_states) -
-                sizeof(states->states) +
-                (states->possible_states_size * sizeof(states->states));
-            states =
-                reinterpret_cast<state_effecter_possible_states*>(nextState);
         }
+        catch (const std::out_of_range& e)
+        {
+            std::cerr << "the effecterId does not exist. effecter id: "
+                      << effecterId << e.what() << '\n';
+        }
+
         return rc;
     }
 
   private:
     pdr_utils::Repo pdrRepo;
     uint16_t nextEffecterId{};
-    std::map<uint16_t, EffecterObjs> effecterObjs{};
+    DbusObjMaps dbusObjMaps{};
 };
 
 } // namespace platform