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