Add responder for Platform Event Message

Provide infrastructure to hook handler for each PLDM event type.

Change-Id: I67480bb923f5eca311b2b0e597a146e020a5baf7
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 6aef73d..0a33d86 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -195,6 +195,89 @@
     return response;
 }
 
+Response Handler::platformEventMessage(const pldm_msg* request,
+                                       size_t payloadLength)
+{
+    uint8_t formatVersion{};
+    uint8_t tid{};
+    uint8_t eventClass{};
+    size_t offset{};
+
+    auto rc = decode_platform_event_message_req(
+        request, payloadLength, &formatVersion, &tid, &eventClass, &offset);
+    if (rc != PLDM_SUCCESS)
+    {
+        return CmdHandler::ccOnlyResponse(request, rc);
+    }
+
+    try
+    {
+        const auto& handlers = eventHandlers.at(eventClass);
+        for (const auto& handler : handlers)
+        {
+            auto rc =
+                handler(request, payloadLength, formatVersion, tid, offset);
+            if (rc != PLDM_SUCCESS)
+            {
+                return CmdHandler::ccOnlyResponse(request, rc);
+            }
+        }
+    }
+    catch (const std::out_of_range& e)
+    {
+        return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA);
+    }
+
+    Response response(
+        sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    rc = encode_platform_event_message_resp(request->hdr.instance_id, rc,
+                                            PLDM_EVENT_NO_LOGGING, responsePtr);
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+
+    return response;
+}
+
+int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength,
+                         uint8_t /*formatVersion*/, uint8_t /*tid*/,
+                         size_t eventDataOffset)
+{
+    uint16_t sensorId{};
+    uint8_t eventClass{};
+    size_t eventClassDataOffset{};
+    auto eventData =
+        reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
+    auto eventDataSize = payloadLength - eventDataOffset;
+
+    auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
+                                       &eventClass, &eventClassDataOffset);
+    if (rc != PLDM_SUCCESS)
+    {
+        return rc;
+    }
+
+    if (eventClass == PLDM_STATE_SENSOR_STATE)
+    {
+        uint8_t sensorOffset{};
+        uint8_t eventState{};
+        uint8_t previousEventState{};
+
+        rc = decode_state_sensor_data(&eventClass, eventClassDataOffset,
+                                      &sensorOffset, &eventState,
+                                      &previousEventState);
+    }
+    else
+    {
+        return PLDM_ERROR_INVALID_DATA;
+    }
+
+    return PLDM_SUCCESS;
+}
+
 } // namespace platform
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 75a1ad3..a435dca 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -31,11 +31,21 @@
 using DbusObjMaps =
     std::map<EffecterId,
              std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>>;
+using DbusPath = std::string;
+using EffecterObjs = std::vector<DbusPath>;
+using EventType = uint8_t;
+using EventHandler = std::function<int(
+    const pldm_msg* request, size_t payloadLength, uint8_t formatVersion,
+    uint8_t tid, size_t eventDataOffset)>;
+using EventHandlers = std::vector<EventHandler>;
+using EventMap = std::map<EventType, EventHandlers>;
 
 class Handler : public CmdHandler
 {
   public:
-    Handler(const std::string& dir, pldm_pdr* repo) : pdrRepo(repo)
+    Handler(const std::string& dir, pldm_pdr* repo,
+            const std::optional<EventMap>& addOnHandlersMap = std::nullopt) :
+        pdrRepo(repo)
     {
         generate(dir, pdrRepo);
 
@@ -48,6 +58,41 @@
                              return this->setStateEffecterStates(request,
                                                                  payloadLength);
                          });
+        handlers.emplace(PLDM_PLATFORM_EVENT_MESSAGE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->platformEventMessage(request,
+                                                               payloadLength);
+                         });
+
+        // Default handler for PLDM Events
+        eventHandlers[PLDM_SENSOR_EVENT].emplace_back(
+            [this](const pldm_msg* request, size_t payloadLength,
+                   uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) {
+                return this->sensorEvent(request, payloadLength, formatVersion,
+                                         tid, eventDataOffset);
+            });
+
+        // Additional OEM event handlers for PLDM events, append it to the
+        // standard handlers
+        if (addOnHandlersMap)
+        {
+            auto addOnHandlers = addOnHandlersMap.value();
+            for (EventMap::iterator iter = addOnHandlers.begin();
+                 iter != addOnHandlers.end(); ++iter)
+            {
+                auto search = eventHandlers.find(iter->first);
+                if (search != eventHandlers.end())
+                {
+                    search->second.insert(std::end(search->second),
+                                          std::begin(iter->second),
+                                          std::end(iter->second));
+                }
+                else
+                {
+                    eventHandlers.emplace(iter->first, iter->second);
+                }
+            }
+        }
     }
 
     pdr_utils::Repo& getRepo()
@@ -97,6 +142,11 @@
      */
     void generateStateEffecterRepo(const Json& json, Repo& repo);
 
+    /** @brief map of PLDM event type to EventHandlers
+     *
+     */
+    EventMap eventHandlers;
+
     /** @brief Handler for GetPDR
      *
      *  @param[in] request - Request message payload
@@ -114,6 +164,28 @@
     Response setStateEffecterStates(const pldm_msg* request,
                                     size_t payloadLength);
 
+    /** @brief Handler for PlatformEventMessage
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payloadLength - Request payload length
+     *  @return Response - PLDM Response message
+     */
+    Response platformEventMessage(const pldm_msg* request,
+                                  size_t payloadLength);
+
+    /** @brief Handler for event class Sensor event
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payloadLength - Request payload length
+     *  @param[in] formatVersion - Version of the event format
+     *  @param[in] tid - Terminus ID of the event's originator
+     *  @param[in] eventDataOffset - Offset of the event data in the request
+     *                               message
+     *  @return PLDM completion code
+     */
+    int sensorEvent(const pldm_msg* request, size_t payloadLength,
+                    uint8_t formatVersion, uint8_t tid, size_t eventDataOffset);
+
     /** @brief Function to set the effecter requested by pldm requester
      *  @param[in] dBusIntf - The interface object
      *  @param[in] effecterId - Effecter ID sent by the requester to act on