1 #pragma once
2 
3 #include "sensorhandler.hpp"
4 
5 #include <cmath>
6 #include <ipmid/api.hpp>
7 #include <ipmid/types.hpp>
8 #include <ipmid/utils.hpp>
9 #include <sdbusplus/message/types.hpp>
10 
11 namespace ipmi
12 {
13 namespace sensor
14 {
15 
16 namespace variant_ns = sdbusplus::message::variant_ns;
17 
18 using Assertion = uint16_t;
19 using Deassertion = uint16_t;
20 using AssertionSet = std::pair<Assertion, Deassertion>;
21 
22 using Service = std::string;
23 using Path = std::string;
24 using Interface = std::string;
25 
26 using ServicePath = std::pair<Path, Service>;
27 
28 using Interfaces = std::vector<Interface>;
29 
30 using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>;
31 
32 /** @brief get the D-Bus service and service path
33  *  @param[in] bus - The Dbus bus object
34  *  @param[in] interface - interface to the service
35  *  @param[in] path - interested path in the list of objects
36  *  @return pair of service path and service
37  */
38 ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
39                               const std::string& interface,
40                               const std::string& path = std::string());
41 
42 /** @brief Make assertion set from input data
43  *  @param[in] cmdData - Input sensor data
44  *  @return pair of assertion and deassertion set
45  */
46 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData);
47 
48 /** @brief send the message to DBus
49  *  @param[in] msg - message to send
50  *  @return failure status in IPMI error code
51  */
52 ipmi_ret_t updateToDbus(IpmiUpdateData& msg);
53 
54 namespace get
55 {
56 
57 /** @brief Populate sensor name from the D-Bus property associated with the
58  *         sensor. In the example entry from the yaml, the name of the D-bus
59  *         property "AttemptsLeft" is the sensor name.
60  *
61  *         0x07:
62  *            sensorType: 195
63  *            path: /xyz/openbmc_project/state/host0
64  *            sensorReadingType: 0x6F
65  *            serviceInterface: org.freedesktop.DBus.Properties
66  *            readingType: readingAssertion
67  *            sensorNamePattern: nameProperty
68  *            interfaces:
69  *              xyz.openbmc_project.Control.Boot.RebootAttempts:
70  *                AttemptsLeft:
71  *                    Offsets:
72  *                        0xFF:
73  *                          type: uint32_t
74  *
75  *
76  *  @param[in] sensorInfo - Dbus info related to sensor.
77  *
78  *  @return On success return the sensor name for the sensor.
79  */
80 inline SensorName nameProperty(const Info& sensorInfo)
81 {
82     return sensorInfo.propertyInterfaces.begin()->second.begin()->first;
83 }
84 
85 /** @brief Populate sensor name from the D-Bus object associated with the
86  *         sensor. If the object path is /system/chassis/motherboard/dimm0 then
87  *         the leaf dimm0 is considered as the sensor name.
88  *
89  *  @param[in] sensorInfo - Dbus info related to sensor.
90  *
91  *  @return On success return the sensor name for the sensor.
92  */
93 inline SensorName nameLeaf(const Info& sensorInfo)
94 {
95     return sensorInfo.sensorPath.substr(
96         sensorInfo.sensorPath.find_last_of('/') + 1,
97         sensorInfo.sensorPath.length());
98 }
99 
100 /** @brief Populate sensor name from the D-Bus object associated with the
101  *         sensor. If the object path is /system/chassis/motherboard/cpu0/core0
102  *         then the sensor name is cpu0_core0. The leaf and the parent is put
103  *         together to get the sensor name.
104  *
105  *  @param[in] sensorInfo - Dbus info related to sensor.
106  *
107  *  @return On success return the sensor name for the sensor.
108  */
109 SensorName nameParentLeaf(const Info& sensorInfo);
110 
111 /**
112  *  @brief Helper function to map the dbus info to sensor's assertion status
113  *         for the get sensor reading command.
114  *
115  *  @param[in] sensorInfo - Dbus info related to sensor.
116  *  @param[in] path - Dbus object path.
117  *  @param[in] interface - Dbus interface.
118  *
119  *  @return Response for get sensor reading command.
120  */
121 GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
122                                      const InstancePath& path,
123                                      const DbusInterface& interface);
124 
125 /**
126  *  @brief Map the Dbus info to sensor's assertion status in the Get sensor
127  *         reading command response.
128  *
129  *  @param[in] sensorInfo - Dbus info related to sensor.
130  *
131  *  @return Response for get sensor reading command.
132  */
133 GetSensorResponse assertion(const Info& sensorInfo);
134 
135 /**
136  *  @brief Maps the Dbus info to the reading field in the Get sensor reading
137  *         command response.
138  *
139  *  @param[in] sensorInfo - Dbus info related to sensor.
140  *
141  *  @return Response for get sensor reading command.
142  */
143 GetSensorResponse eventdata2(const Info& sensorInfo);
144 
145 /**
146  *  @brief readingAssertion is a case where the entire assertion state field
147  *         serves as the sensor value.
148  *
149  *  @tparam T - type of the dbus property related to sensor.
150  *  @param[in] sensorInfo - Dbus info related to sensor.
151  *
152  *  @return Response for get sensor reading command.
153  */
154 template <typename T>
155 GetSensorResponse readingAssertion(const Info& sensorInfo)
156 {
157     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
158     GetSensorResponse response{};
159     auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
160 
161     auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
162                                     sensorInfo.sensorPath);
163 
164     auto propValue = ipmi::getDbusProperty(
165         bus, service, sensorInfo.sensorPath,
166         sensorInfo.propertyInterfaces.begin()->first,
167         sensorInfo.propertyInterfaces.begin()->second.begin()->first);
168 
169     setAssertionBytes(static_cast<uint16_t>(variant_ns::get<T>(propValue)),
170                       responseData);
171 
172     return response;
173 }
174 
175 /** @brief Map the Dbus info to the reading field in the Get sensor reading
176  *         command response
177  *
178  *  @tparam T - type of the dbus property related to sensor.
179  *  @param[in] sensorInfo - Dbus info related to sensor.
180  *
181  *  @return Response for get sensor reading command.
182  */
183 template <typename T>
184 GetSensorResponse readingData(const Info& sensorInfo)
185 {
186     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
187     GetSensorResponse response{};
188     auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
189 
190     enableScanning(responseData);
191 
192     auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
193                                     sensorInfo.sensorPath);
194 
195     auto propValue = ipmi::getDbusProperty(
196         bus, service, sensorInfo.sensorPath,
197         sensorInfo.propertyInterfaces.begin()->first,
198         sensorInfo.propertyInterfaces.begin()->second.begin()->first);
199 
200     double value = variant_ns::get<T>(propValue) *
201                    std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
202 
203     auto rawData = static_cast<uint8_t>((value - sensorInfo.scaledOffset) /
204                                         sensorInfo.coefficientM);
205 
206     setReading(rawData, responseData);
207 
208     return response;
209 }
210 
211 } // namespace get
212 
213 namespace set
214 {
215 
216 /** @brief Make a DBus message for a Dbus call
217  *  @param[in] updateInterface - Interface name
218  *  @param[in] sensorPath - Path of the sensor
219  *  @param[in] command - command to be executed
220  *  @param[in] sensorInterface - DBus interface of sensor
221  *  @return a dbus message
222  */
223 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
224                            const std::string& sensorPath,
225                            const std::string& command,
226                            const std::string& sensorInterface);
227 
228 /** @brief Update d-bus based on assertion type sensor data
229  *  @param[in] cmdData - input sensor data
230  *  @param[in] sensorInfo - sensor d-bus info
231  *  @return a IPMI error code
232  */
233 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
234                      const Info& sensorInfo);
235 
236 /** @brief Update d-bus based on a reading assertion
237  *  @tparam T - type of d-bus property mapping this sensor
238  *  @param[in] cmdData - input sensor data
239  *  @param[in] sensorInfo - sensor d-bus info
240  *  @return a IPMI error code
241  */
242 template <typename T>
243 ipmi_ret_t readingAssertion(const SetSensorReadingReq& cmdData,
244                             const Info& sensorInfo)
245 {
246     auto msg =
247         makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
248                     "Set", sensorInfo.sensorInterface);
249 
250     const auto& interface = sensorInfo.propertyInterfaces.begin();
251     msg.append(interface->first);
252     for (const auto& property : interface->second)
253     {
254         msg.append(property.first);
255         sdbusplus::message::variant<T> value =
256             (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7;
257         msg.append(value);
258     }
259     return updateToDbus(msg);
260 }
261 
262 /** @brief Update d-bus based on a discrete reading
263  *  @param[in] cmdData - input sensor data
264  *  @param[in] sensorInfo - sensor d-bus info
265  *  @return an IPMI error code
266  */
267 template <typename T>
268 ipmi_ret_t readingData(const SetSensorReadingReq& cmdData,
269                        const Info& sensorInfo)
270 {
271     T raw_value =
272         (sensorInfo.coefficientM * cmdData.reading) + sensorInfo.scaledOffset;
273 
274     raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale);
275 
276     auto msg =
277         makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
278                     "Set", sensorInfo.sensorInterface);
279 
280     const auto& interface = sensorInfo.propertyInterfaces.begin();
281     msg.append(interface->first);
282 
283     for (const auto& property : interface->second)
284     {
285         msg.append(property.first);
286         sdbusplus::message::variant<T> value = raw_value;
287         msg.append(value);
288     }
289     return updateToDbus(msg);
290 }
291 
292 /** @brief Update d-bus based on eventdata type sensor data
293  *  @param[in] cmdData - input sensor data
294  *  @param[in] sensorInfo - sensor d-bus info
295  *  @return a IPMI error code
296  */
297 ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
298                      uint8_t data);
299 
300 /** @brief Update d-bus based on eventdata1 type sensor data
301  *  @param[in] cmdData - input sensor data
302  *  @param[in] sensorInfo - sensor d-bus info
303  *  @return a IPMI error code
304  */
305 inline ipmi_ret_t eventdata1(const SetSensorReadingReq& cmdData,
306                              const Info& sensorInfo)
307 {
308     return eventdata(cmdData, sensorInfo, cmdData.eventData1);
309 }
310 
311 /** @brief Update d-bus based on eventdata2 type sensor data
312  *  @param[in] cmdData - input sensor data
313  *  @param[in] sensorInfo - sensor d-bus info
314  *  @return a IPMI error code
315  */
316 inline ipmi_ret_t eventdata2(const SetSensorReadingReq& cmdData,
317                              const Info& sensorInfo)
318 {
319     return eventdata(cmdData, sensorInfo, cmdData.eventData2);
320 }
321 
322 /** @brief Update d-bus based on eventdata3 type sensor data
323  *  @param[in] cmdData - input sensor data
324  *  @param[in] sensorInfo - sensor d-bus info
325  *  @return a IPMI error code
326  */
327 inline ipmi_ret_t eventdata3(const SetSensorReadingReq& cmdData,
328                              const Info& sensorInfo)
329 {
330     return eventdata(cmdData, sensorInfo, cmdData.eventData3);
331 }
332 
333 } // namespace set
334 
335 namespace notify
336 {
337 
338 /** @brief Make a DBus message for a Dbus call
339  *  @param[in] updateInterface - Interface name
340  *  @param[in] sensorPath - Path of the sensor
341  *  @param[in] command - command to be executed
342  *  @param[in] sensorInterface - DBus interface of sensor
343  *  @return a dbus message
344  */
345 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
346                            const std::string& sensorPath,
347                            const std::string& command,
348                            const std::string& sensorInterface);
349 
350 /** @brief Update d-bus based on assertion type sensor data
351  *  @param[in] interfaceMap - sensor interface
352  *  @param[in] cmdData - input sensor data
353  *  @param[in] sensorInfo - sensor d-bus info
354  *  @return a IPMI error code
355  */
356 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
357                      const Info& sensorInfo);
358 
359 } // namespace notify
360 
361 namespace inventory
362 {
363 
364 namespace get
365 {
366 
367 /**
368  *  @brief Map the Dbus info to sensor's assertion status in the Get sensor
369  *         reading command response.
370  *
371  *  @param[in] sensorInfo - Dbus info related to sensor.
372  *
373  *  @return Response for get sensor reading command.
374  */
375 GetSensorResponse assertion(const Info& sensorInfo);
376 
377 } // namespace get
378 
379 } // namespace inventory
380 } // namespace sensor
381 } // namespace ipmi
382