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