pldm_events: Parse state sensor PDRs from the Host PDR

Parse the State Sensor PDRs from the host firmware and build
the HostStateSensorMap data structure which will be used to
lookup the sensor info for the sensorEventType in the
PlatformEventMessage command. Also clear the HostStateSensorMap
when the host powers off.

Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Change-Id: Id85a73f1a0a1caf4b4155a8d235b3e807383e53a
diff --git a/libpldmresponder/pdr_utils.cpp b/libpldmresponder/pdr_utils.cpp
index 85af37f..8819e67 100644
--- a/libpldmresponder/pdr_utils.cpp
+++ b/libpldmresponder/pdr_utils.cpp
@@ -1,5 +1,9 @@
 #include "pdr.hpp"
 
+#include <climits>
+
+#include "libpldm/platform.h"
+
 namespace pldm
 {
 
@@ -135,6 +139,54 @@
     return valueMap;
 }
 
+std::tuple<TerminusHandle, SensorID, SensorInfo>
+    parseStateSensorPDR(const std::vector<uint8_t>& stateSensorPdr)
+{
+    auto pdr =
+        reinterpret_cast<const pldm_state_sensor_pdr*>(stateSensorPdr.data());
+    CompositeSensorStates sensors{};
+    auto statesPtr = pdr->possible_states;
+    auto compositeSensorCount = pdr->composite_sensor_count;
+
+    while (compositeSensorCount--)
+    {
+        auto state =
+            reinterpret_cast<const state_sensor_possible_states*>(statesPtr);
+        PossibleStates possibleStates{};
+        uint8_t possibleStatesPos{};
+        auto updateStates = [&possibleStates,
+                             &possibleStatesPos](const bitfield8_t& val) {
+            for (int i = 0; i < CHAR_BIT; i++)
+            {
+                if (val.byte & (1 << i))
+                {
+                    possibleStates.insert(possibleStatesPos * CHAR_BIT + i);
+                }
+            }
+            possibleStatesPos++;
+        };
+        std::for_each(&state->states[0],
+                      &state->states[state->possible_states_size],
+                      updateStates);
+
+        sensors.emplace_back(std::move(possibleStates));
+        if (compositeSensorCount)
+        {
+            statesPtr += sizeof(state_sensor_possible_states) +
+                         state->possible_states_size - 1;
+        }
+    }
+
+    auto entityInfo =
+        std::make_tuple(static_cast<ContainerID>(pdr->container_id),
+                        static_cast<EntityType>(pdr->entity_type),
+                        static_cast<EntityInstance>(pdr->entity_instance));
+    auto sensorInfo =
+        std::make_tuple(std::move(entityInfo), std::move(sensors));
+    return std::make_tuple(pdr->terminus_handle, pdr->sensor_id,
+                           std::move(sensorInfo));
+}
+
 } // namespace pdr_utils
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/pdr_utils.hpp b/libpldmresponder/pdr_utils.hpp
index 6df5d94..8f4f825 100644
--- a/libpldmresponder/pdr_utils.hpp
+++ b/libpldmresponder/pdr_utils.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "types.hpp"
 #include "utils.hpp"
 
 #include <stdint.h>
@@ -195,6 +196,18 @@
     bool empty() override;
 };
 
+using namespace pldm::pdr;
+/** @brief Parse the State Sensor PDR and return the parsed sensor info which
+ *         will be used to lookup the sensor info in the PlatformEventMessage
+ *         command of sensorEvent type.
+ *
+ *  @param[in] stateSensorPdr - state sensor PDR
+ *
+ *  @return terminus handle, sensor ID and parsed sensor info
+ */
+std::tuple<TerminusHandle, SensorID, SensorInfo>
+    parseStateSensorPDR(const std::vector<uint8_t>& stateSensorPdr);
+
 } // namespace pdr_utils
 } // namespace responder
 } // namespace pldm