1 #pragma once
2 
3 #include "common/utils.hpp"
4 #include "libpldmresponder/pdr.hpp"
5 #include "pdr_utils.hpp"
6 #include "pldmd/handler.hpp"
7 
8 #include <libpldm/platform.h>
9 #include <libpldm/states.h>
10 
11 #include <phosphor-logging/lg2.hpp>
12 
13 #include <cstdint>
14 #include <map>
15 
16 PHOSPHOR_LOG2_USING;
17 
18 namespace pldm
19 {
20 namespace responder
21 {
22 namespace platform_state_sensor
23 {
24 /** @brief Function to get the sensor state
25  *
26  *  @tparam[in] DBusInterface - DBus interface type
27  *  @param[in] dBusIntf - The interface object of DBusInterface
28  *  @param[in] stateToDbusValue - Map of DBus property State to attribute value
29  *  @param[in] dbusMapping - The d-bus object
30  *
31  *  @return - Enumeration of SensorState
32  */
33 template <class DBusInterface>
34 uint8_t getStateSensorEventState(
35     const DBusInterface& dBusIntf,
36     const std::map<pldm::responder::pdr_utils::State,
37                    pldm::utils::PropertyValue>& stateToDbusValue,
38     const pldm::utils::DBusMapping& dbusMapping)
39 {
40     try
41     {
42         auto propertyValue = dBusIntf.getDbusPropertyVariant(
43             dbusMapping.objectPath.c_str(), dbusMapping.propertyName.c_str(),
44             dbusMapping.interface.c_str());
45 
46         for (const auto& stateValue : stateToDbusValue)
47         {
48             if (stateValue.second == propertyValue)
49             {
50                 return stateValue.first;
51             }
52         }
53     }
54     catch (const std::exception& e)
55     {
56         error(
57             "Failed to get state sensor event state from dbus interface '{PATH}', error - {ERROR}.",
58             "PATH", dbusMapping.objectPath.c_str(), "ERROR", e);
59     }
60 
61     return PLDM_SENSOR_UNKNOWN;
62 }
63 
64 /** @brief Function to get the state sensor readings requested by pldm requester
65  *
66  *  @tparam[in] DBusInterface - DBus interface type
67  *  @tparam[in] Handler - pldm::responder::platform::Handler
68  *  @param[in] dBusIntf - The interface object of DBusInterface
69  *  @param[in] handler - The interface object of
70  *             pldm::responder::platform::Handler
71  *  @param[in] sensorId - Sensor ID sent by the requester to act on
72  *  @param[in] sensorRearmCnt - Each bit location in this field corresponds to a
73  *              particular sensor within the state sensor
74  *  @param[out] compSensorCnt - composite sensor count
75  *  @param[out] stateField - The state field data for each of the states,
76  *              equal to composite sensor count in number
77  *  @return - Success or failure in setting the states. Returns failure in
78  * terms of PLDM completion codes if atleast one state fails to be set
79  */
80 template <class DBusInterface, class Handler>
81 int getStateSensorReadingsHandler(
82     const DBusInterface& dBusIntf, Handler& handler, uint16_t sensorId,
83     uint8_t sensorRearmCnt, uint8_t& compSensorCnt,
84     std::vector<get_sensor_state_field>& stateField,
85     const stateSensorCacheMaps& sensorCache)
86 {
87     using namespace pldm::responder::pdr;
88     using namespace pldm::utils;
89 
90     pldm_state_sensor_pdr* pdr = nullptr;
91 
92     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
93         pldm_pdr_init(), pldm_pdr_destroy);
94     if (!stateSensorPdrRepo)
95     {
96         throw std::runtime_error(
97             "Failed to instantiate state sensor PDR repository");
98     }
99     pldm::responder::pdr_utils::Repo stateSensorPDRs(stateSensorPdrRepo.get());
100     getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
101     if (stateSensorPDRs.empty())
102     {
103         error("Failed to get StateSensorPDR record.");
104         return PLDM_PLATFORM_INVALID_SENSOR_ID;
105     }
106 
107     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
108     auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
109     while (pdrRecord)
110     {
111         pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
112         assert(pdr != NULL);
113         if (pdr->sensor_id != sensorId)
114         {
115             pdr = nullptr;
116             pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
117             continue;
118         }
119 
120         compSensorCnt = pdr->composite_sensor_count;
121         if (sensorRearmCnt > compSensorCnt)
122         {
123             error(
124                 "The requester sent wrong sensor rearm count '{SENSOR_REARM_COUNT}' for the sensor ID '{SENSORID}'",
125                 "SENSORID", sensorId, "SENSOR_REARM_COUNT", sensorRearmCnt);
126             return PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE;
127         }
128 
129         if (sensorRearmCnt == 0)
130         {
131             sensorRearmCnt = compSensorCnt;
132             stateField.resize(sensorRearmCnt);
133         }
134 
135         break;
136     }
137 
138     if (!pdr)
139     {
140         return PLDM_PLATFORM_INVALID_SENSOR_ID;
141     }
142 
143     int rc = PLDM_SUCCESS;
144     try
145     {
146         const auto& [dbusMappings, dbusValMaps] = handler.getDbusObjMaps(
147             sensorId, pldm::responder::pdr_utils::TypeId::PLDM_SENSOR_ID);
148 
149         if (dbusMappings.empty() || dbusValMaps.empty())
150         {
151             error("DbusMappings for sensor ID '{SENSOR_ID}' is missing",
152                   "SENSOR_ID", sensorId);
153             return PLDM_ERROR;
154         }
155         pldm::responder::pdr_utils::EventStates sensorCacheforSensor{};
156         if (sensorCache.contains(sensorId))
157         {
158             sensorCacheforSensor = sensorCache.at(sensorId);
159         }
160         stateField.clear();
161         for (std::size_t offset{0};
162              offset < sensorRearmCnt && offset < dbusMappings.size() &&
163              offset < dbusValMaps.size();
164              offset++)
165         {
166             auto& dbusMapping = dbusMappings[offset];
167 
168             uint8_t sensorEvent = getStateSensorEventState<DBusInterface>(
169                 dBusIntf, dbusValMaps[offset], dbusMapping);
170 
171             uint8_t previousState = PLDM_SENSOR_UNKNOWN;
172 
173             // if sensor cache is empty, then its the first
174             // get_state_sensor_reading on this sensor, set the previous state
175             // as the current state
176 
177             if (sensorCacheforSensor.at(offset) == PLDM_SENSOR_UNKNOWN)
178             {
179                 previousState = sensorEvent;
180                 handler.updateSensorCache(sensorId, offset, previousState);
181             }
182             else
183             {
184                 // sensor cache is not empty, so get the previous state from
185                 // the sensor cache
186                 previousState = sensorCacheforSensor[offset];
187             }
188             uint8_t opState = PLDM_SENSOR_ENABLED;
189             if (sensorEvent == PLDM_SENSOR_UNKNOWN)
190             {
191                 opState = PLDM_SENSOR_UNAVAILABLE;
192             }
193 
194             stateField.push_back(
195                 {opState, PLDM_SENSOR_NORMAL, previousState, sensorEvent});
196         }
197     }
198     catch (const std::out_of_range& e)
199     {
200         error("The sensor ID '{SENSORID}' does not exist, error - {ERROR}",
201               "SENSORID", sensorId, "ERROR", e);
202         rc = PLDM_ERROR;
203     }
204 
205     return rc;
206 }
207 
208 } // namespace platform_state_sensor
209 } // namespace responder
210 } // namespace pldm
211