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