libpldmresponder: Implement GetStateSensorReadings

Register the getStateSensorReadings method and get the state sensor PDR
structure according to the SensorId property.

Tested with JSON file:
https://gist.github.com/lxwinspur/6a40abea7330c25e4d49826e890c4be9

pldmtool raw -d 0x80 0x02 0x21 0x01 0x00 0x01 0x00
Request Message:
08 01 80 02 21 01 00 01 00
Response Message:
08 01 00 02 21 00 01 03 00 00 00

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I4faeb1e85f9fd4a2745f592d37be38c28112f5b9
diff --git a/libpldm/platform.h b/libpldm/platform.h
index 7834f59..bd4d557 100644
--- a/libpldm/platform.h
+++ b/libpldm/platform.h
@@ -157,6 +157,9 @@
 /** @brief PLDM Platform M&C completion codes
  */
 enum pldm_platform_completion_codes {
+	PLDM_PLATFORM_INVALID_SENSOR_ID = 0x80,
+	PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE = 0x81,
+
 	PLDM_PLATFORM_INVALID_EFFECTER_ID = 0x80,
 	PLDM_PLATFORM_INVALID_STATE_VALUE = 0x81,
 
diff --git a/libpldmresponder/pdr_utils.hpp b/libpldmresponder/pdr_utils.hpp
index c463f1f..9406d46 100644
--- a/libpldmresponder/pdr_utils.hpp
+++ b/libpldmresponder/pdr_utils.hpp
@@ -89,6 +89,26 @@
     return Json::parse(jsonFile);
 }
 
+/** @brief Function to get the Bitfield count to 1
+ *
+ *  @param[in] bit - Bitfield
+ *
+ *  @return - uint8_t return the number of 1
+ */
+inline uint8_t getBitfieldCount(const bitfield8_t bit)
+{
+    uint8_t count = 0;
+    for (uint8_t i = 0; i < 8; ++i)
+    {
+        if (bit.byte & (1 << i))
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
 /** @brief Populate the mapping between D-Bus property stateId and attribute
  *          value for the effecter PDR enumeration attribute.
  *
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 61d09ad..c017486 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -7,8 +7,10 @@
 #include "pdr_numeric_effecter.hpp"
 #include "pdr_state_effecter.hpp"
 #include "pdr_state_sensor.hpp"
+#include "pdr_utils.hpp"
 #include "platform_numeric_effecter.hpp"
 #include "platform_state_effecter.hpp"
+#include "platform_state_sensor.hpp"
 
 namespace pldm
 {
@@ -614,6 +616,56 @@
     pdrEntry.size = pdrBuffer.size();
     repo.addRecord(pdrEntry);
 }
+
+Response Handler::getStateSensorReadings(const pldm_msg* request,
+                                         size_t payloadLength)
+{
+    uint16_t sensorId{};
+    bitfield8_t sensorRearm{};
+    uint8_t reserved{};
+
+    if (payloadLength != PLDM_GET_SENSOR_READING_REQ_BYTES)
+    {
+        return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
+    }
+
+    int rc = decode_get_state_sensor_readings_req(
+        request, payloadLength, &sensorId, &sensorRearm, &reserved);
+
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+
+    // 0x01 to 0x08
+    uint8_t sensorRearmCout = getBitfieldCount(sensorRearm);
+    std::vector<get_sensor_state_field> stateField(sensorRearmCout);
+    uint8_t comSensorCnt{};
+    const pldm::utils::DBusHandler dBusIntf;
+    rc = platform_state_sensor::getStateSensorReadingsHandler<
+        pldm::utils::DBusHandler, Handler>(
+        dBusIntf, *this, sensorId, sensorRearmCout, comSensorCnt, stateField);
+
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+
+    Response response(sizeof(pldm_msg_hdr) +
+                      PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES +
+                      sizeof(get_sensor_state_field) * comSensorCnt);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc,
+                                               comSensorCnt, stateField.data(),
+                                               responsePtr);
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+
+    return response;
+}
+
 } // namespace platform
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 06496dc..6d6fd95 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -92,6 +92,11 @@
                              return this->platformEventMessage(request,
                                                                payloadLength);
                          });
+        handlers.emplace(PLDM_GET_STATE_SENSOR_READINGS,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getStateSensorReadings(request,
+                                                                 payloadLength);
+                         });
 
         // Default handler for PLDM Events
         eventHandlers[PLDM_SENSOR_EVENT].emplace_back(
@@ -211,6 +216,15 @@
     Response setNumericEffecterValue(const pldm_msg* request,
                                      size_t payloadLength);
 
+    /** @brief Handler for getStateSensorReadings
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payloadLength - Request payload length
+     *  @return Response - PLDM Response message
+     */
+    Response getStateSensorReadings(const pldm_msg* request,
+                                    size_t payloadLength);
+
     /** @brief Handler for setStateEffecterStates
      *
      *  @param[in] request - Request message
diff --git a/libpldmresponder/platform_state_sensor.hpp b/libpldmresponder/platform_state_sensor.hpp
new file mode 100644
index 0000000..3fd55cd
--- /dev/null
+++ b/libpldmresponder/platform_state_sensor.hpp
@@ -0,0 +1,157 @@
+#pragma once
+
+#include "config.h"
+
+#include "libpldm/platform.h"
+#include "libpldm/states.h"
+
+#include "common/utils.hpp"
+#include "libpldmresponder/pdr.hpp"
+#include "pdr_utils.hpp"
+#include "pldmd/handler.hpp"
+
+#include <cstdint>
+#include <map>
+
+using namespace pldm::responder::pdr;
+
+namespace pldm
+{
+namespace responder
+{
+namespace platform_state_sensor
+{
+
+/** @brief Function to get the sensor state
+ *
+ *  @tparam[in] DBusInterface - DBus interface type
+ *  @param[in] dBusIntf - The interface object of DBusInterface
+ *  @param[in] stateToDbusValue - Map of DBus property State to attribute value
+ *  @param[in] dbusMapping - The d-bus object
+ *
+ *  @return - Enumeration of SensorState
+ */
+template <class DBusInterface>
+uint8_t getStateSensorEventState(
+    const DBusInterface& dBusIntf,
+    const std::map<State, pldm::utils::PropertyValue>& stateToDbusValue,
+    const DBusMapping& dbusMapping)
+{
+    try
+    {
+        auto propertyValue = dBusIntf.getDbusPropertyVariant(
+            dbusMapping.objectPath.c_str(), dbusMapping.propertyName.c_str(),
+            dbusMapping.interface.c_str());
+
+        for (const auto& stateValue : stateToDbusValue)
+        {
+            if (stateValue.second == propertyValue)
+            {
+                return stateValue.first;
+            }
+        }
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << e.what() << '\n';
+    }
+
+    return PLDM_SENSOR_DISABLED;
+}
+
+/** @brief Function to get the state sensor readings requested by pldm requester
+ *
+ *  @tparam[in] DBusInterface - DBus interface type
+ *  @tparam[in] Handler - pldm::responder::platform::Handler
+ *  @param[in] dBusIntf - The interface object of DBusInterface
+ *  @param[in] handler - The interface object of
+ *             pldm::responder::platform::Handler
+ *  @param[in] sensorId - Sensor ID sent by the requester to act on
+ *  @param[in] sensorRearmCnt - Each bit location in this field corresponds to a
+ *              particular sensor within the state sensor
+ *  @param[out] compSensorCnt - composite sensor count
+ *  @param[out] stateField - The state field data for each of the states,
+ *              equal to composite sensor count in number
+ *  @return - Success or failure in setting the states. Returns failure in
+ * terms of PLDM completion codes if atleast one state fails to be set
+ */
+template <class DBusInterface, class Handler>
+int getStateSensorReadingsHandler(
+    const DBusInterface& dBusIntf, Handler& handler, uint16_t sensorId,
+    uint8_t sensorRearmCnt, uint8_t& compSensorCnt,
+    std::vector<get_sensor_state_field>& stateField)
+{
+    using namespace pldm::responder::pdr;
+    using namespace pldm::utils;
+
+    pldm_state_sensor_pdr* pdr = nullptr;
+
+    std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
+        pldm_pdr_init(), pldm_pdr_destroy);
+    Repo stateSensorPDRs(stateSensorPdrRepo.get());
+    getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
+    if (stateSensorPDRs.empty())
+    {
+        std::cerr << "Failed to get record by PDR type\n";
+        return PLDM_PLATFORM_INVALID_SENSOR_ID;
+    }
+
+    PdrEntry pdrEntry{};
+    auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
+    while (pdrRecord)
+    {
+        pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
+        assert(pdr != NULL);
+        if (pdr->sensor_id != sensorId)
+        {
+            pdr = nullptr;
+            pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
+            continue;
+        }
+
+        compSensorCnt = pdr->composite_sensor_count;
+        if (sensorRearmCnt > compSensorCnt)
+        {
+            std::cerr << "The requester sent wrong sensorRearm"
+                      << " count for the sensor, SENSOR_ID=" << sensorId
+                      << "SENSOR_REARM_COUNT=" << sensorRearmCnt << "\n";
+            return PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE;
+        }
+        break;
+    }
+
+    if (!pdr)
+    {
+        return PLDM_PLATFORM_INVALID_SENSOR_ID;
+    }
+
+    int rc = PLDM_SUCCESS;
+    try
+    {
+        const auto& [dbusMappings, dbusValMaps] =
+            handler.getDbusObjMaps(sensorId, TypeId::PLDM_SENSOR_ID);
+
+        stateField.clear();
+        for (size_t i = 0; i < compSensorCnt; i++)
+        {
+            auto& dbusMapping = dbusMappings[i];
+
+            uint8_t sensorOpState = getStateSensorEventState<DBusInterface>(
+                dBusIntf, dbusValMaps[i], dbusMapping);
+            stateField.push_back({PLDM_SENSOR_ENABLED, PLDM_SENSOR_UNKNOWN,
+                                  PLDM_SENSOR_UNKNOWN, sensorOpState});
+        }
+    }
+    catch (const std::out_of_range& e)
+    {
+        std::cerr << "the sensorId does not exist. sensor id: " << sensorId
+                  << e.what() << '\n';
+        rc = PLDM_ERROR;
+    }
+
+    return rc;
+}
+
+} // namespace platform_state_sensor
+} // namespace responder
+} // namespace pldm