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 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>(std::get<T>(propValue)),
168                       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, sensorInfo.sensorInterface,
191                                     sensorInfo.sensorPath);
192 
193     auto propValue = ipmi::getDbusProperty(
194         bus, service, sensorInfo.sensorPath,
195         sensorInfo.propertyInterfaces.begin()->first,
196         sensorInfo.propertyInterfaces.begin()->second.begin()->first);
197 
198     double value = std::get<T>(propValue) *
199                    std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
200 
201     auto rawData = static_cast<uint8_t>((value - sensorInfo.scaledOffset) /
202                                         sensorInfo.coefficientM);
203 
204     setReading(rawData, responseData);
205 
206     return response;
207 }
208 
209 } // namespace get
210 
211 namespace set
212 {
213 
214 /** @brief Make a DBus message for a Dbus call
215  *  @param[in] updateInterface - Interface name
216  *  @param[in] sensorPath - Path of the sensor
217  *  @param[in] command - command to be executed
218  *  @param[in] sensorInterface - DBus interface of sensor
219  *  @return a dbus message
220  */
221 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
222                            const std::string& sensorPath,
223                            const std::string& command,
224                            const std::string& sensorInterface);
225 
226 /** @brief Update d-bus based on assertion type sensor data
227  *  @param[in] cmdData - input sensor data
228  *  @param[in] sensorInfo - sensor d-bus info
229  *  @return a IPMI error code
230  */
231 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
232                      const Info& sensorInfo);
233 
234 /** @brief Update d-bus based on a reading assertion
235  *  @tparam T - type of d-bus property mapping this sensor
236  *  @param[in] cmdData - input sensor data
237  *  @param[in] sensorInfo - sensor d-bus info
238  *  @return a IPMI error code
239  */
240 template <typename T>
241 ipmi_ret_t readingAssertion(const SetSensorReadingReq& cmdData,
242                             const Info& sensorInfo)
243 {
244     auto msg =
245         makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
246                     "Set", sensorInfo.sensorInterface);
247 
248     const auto& interface = sensorInfo.propertyInterfaces.begin();
249     msg.append(interface->first);
250     for (const auto& property : interface->second)
251     {
252         msg.append(property.first);
253         std::variant<T> value =
254             (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7;
255         msg.append(value);
256     }
257     return updateToDbus(msg);
258 }
259 
260 /** @brief Update d-bus based on a discrete reading
261  *  @param[in] cmdData - input sensor data
262  *  @param[in] sensorInfo - sensor d-bus info
263  *  @return an IPMI error code
264  */
265 template <typename T>
266 ipmi_ret_t readingData(const SetSensorReadingReq& cmdData,
267                        const Info& sensorInfo)
268 {
269     T raw_value =
270         (sensorInfo.coefficientM * cmdData.reading) + sensorInfo.scaledOffset;
271 
272     raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale);
273 
274     auto msg =
275         makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
276                     "Set", sensorInfo.sensorInterface);
277 
278     const auto& interface = sensorInfo.propertyInterfaces.begin();
279     msg.append(interface->first);
280 
281     for (const auto& property : interface->second)
282     {
283         msg.append(property.first);
284         std::variant<T> value = raw_value;
285         msg.append(value);
286     }
287     return updateToDbus(msg);
288 }
289 
290 /** @brief Update d-bus based on eventdata type sensor data
291  *  @param[in] cmdData - input sensor data
292  *  @param[in] sensorInfo - sensor d-bus info
293  *  @return a IPMI error code
294  */
295 ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
296                      uint8_t data);
297 
298 /** @brief Update d-bus based on eventdata1 type sensor data
299  *  @param[in] cmdData - input sensor data
300  *  @param[in] sensorInfo - sensor d-bus info
301  *  @return a IPMI error code
302  */
303 inline ipmi_ret_t eventdata1(const SetSensorReadingReq& cmdData,
304                              const Info& sensorInfo)
305 {
306     return eventdata(cmdData, sensorInfo, cmdData.eventData1);
307 }
308 
309 /** @brief Update d-bus based on eventdata2 type sensor data
310  *  @param[in] cmdData - input sensor data
311  *  @param[in] sensorInfo - sensor d-bus info
312  *  @return a IPMI error code
313  */
314 inline ipmi_ret_t eventdata2(const SetSensorReadingReq& cmdData,
315                              const Info& sensorInfo)
316 {
317     return eventdata(cmdData, sensorInfo, cmdData.eventData2);
318 }
319 
320 /** @brief Update d-bus based on eventdata3 type sensor data
321  *  @param[in] cmdData - input sensor data
322  *  @param[in] sensorInfo - sensor d-bus info
323  *  @return a IPMI error code
324  */
325 inline ipmi_ret_t eventdata3(const SetSensorReadingReq& cmdData,
326                              const Info& sensorInfo)
327 {
328     return eventdata(cmdData, sensorInfo, cmdData.eventData3);
329 }
330 
331 } // namespace set
332 
333 namespace notify
334 {
335 
336 /** @brief Make a DBus message for a Dbus call
337  *  @param[in] updateInterface - Interface name
338  *  @param[in] sensorPath - Path of the sensor
339  *  @param[in] command - command to be executed
340  *  @param[in] sensorInterface - DBus interface of sensor
341  *  @return a dbus message
342  */
343 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
344                            const std::string& sensorPath,
345                            const std::string& command,
346                            const std::string& sensorInterface);
347 
348 /** @brief Update d-bus based on assertion type sensor data
349  *  @param[in] interfaceMap - sensor interface
350  *  @param[in] cmdData - input sensor data
351  *  @param[in] sensorInfo - sensor d-bus info
352  *  @return a IPMI error code
353  */
354 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
355                      const Info& sensorInfo);
356 
357 } // namespace notify
358 
359 namespace inventory
360 {
361 
362 namespace get
363 {
364 
365 /**
366  *  @brief Map the Dbus info to sensor's assertion status in the Get sensor
367  *         reading command response.
368  *
369  *  @param[in] sensorInfo - Dbus info related to sensor.
370  *
371  *  @return Response for get sensor reading command.
372  */
373 GetSensorResponse assertion(const Info& sensorInfo);
374 
375 } // namespace get
376 
377 } // namespace inventory
378 } // namespace sensor
379 } // namespace ipmi
380