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