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