1 #pragma once
2
3 #include "config.h"
4
5 #include "sensorhandler.hpp"
6
7 #include <ipmid/api.hpp>
8 #include <ipmid/types.hpp>
9 #include <ipmid/utils.hpp>
10 #include <phosphor-logging/elog-errors.hpp>
11 #include <phosphor-logging/lg2.hpp>
12 #include <sdbusplus/message/types.hpp>
13 #include <xyz/openbmc_project/Sensor/Threshold/Critical/common.hpp>
14 #include <xyz/openbmc_project/Sensor/Threshold/Warning/common.hpp>
15 #include <xyz/openbmc_project/Sensor/Value/common.hpp>
16
17 #include <cmath>
18
19 #ifdef FEATURE_SENSORS_CACHE
20
21 extern ipmi::sensor::SensorCacheMap sensorCacheMap;
22
23 // The signal's message type is 0x04 from DBus spec:
24 // https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
25 static constexpr auto msgTypeSignal = 0x04;
26
27 #endif
28
29 namespace ipmi
30 {
31 namespace sensor
32 {
33
34 using Assertion = uint16_t;
35 using Deassertion = uint16_t;
36 using AssertionSet = std::pair<Assertion, Deassertion>;
37 using Service = std::string;
38 using Path = std::string;
39 using Interface = std::string;
40 using ServicePath = std::pair<Path, Service>;
41 using Interfaces = std::vector<Interface>;
42 using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>;
43 using PropertyMap = ipmi::PropertyMap;
44
45 using SensorValue = sdbusplus::common::xyz::openbmc_project::sensor::Value;
46 using SensorThresholdWarning =
47 sdbusplus::common::xyz::openbmc_project::sensor::threshold::Warning;
48 using SensorThresholdCritical =
49 sdbusplus::common::xyz::openbmc_project::sensor::threshold::Critical;
50
51 using namespace phosphor::logging;
52
53 /** @brief Make assertion set from input data
54 * @param[in] cmdData - Input sensor data
55 * @return pair of assertion and deassertion set
56 */
57 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData);
58
59 /** @brief send the message to DBus
60 * @param[in] msg - message to send
61 * @return failure status in IPMI error code
62 */
63 ipmi::Cc updateToDbus(IpmiUpdateData& msg);
64
65 namespace get
66 {
67
68 /** @brief Populate sensor name from the D-Bus property associated with the
69 * sensor. In the example entry from the yaml, the name of the D-bus
70 * property "AttemptsLeft" is the sensor name.
71 *
72 * 0x07:
73 * sensorType: 195
74 * path: /xyz/openbmc_project/state/host0
75 * sensorReadingType: 0x6F
76 * serviceInterface: org.freedesktop.DBus.Properties
77 * readingType: readingAssertion
78 * sensorNamePattern: nameProperty
79 * interfaces:
80 * xyz.openbmc_project.Control.Boot.RebootAttempts:
81 * AttemptsLeft:
82 * Offsets:
83 * 0xFF:
84 * type: uint32_t
85 *
86 *
87 * @param[in] sensorInfo - Dbus info related to sensor.
88 *
89 * @return On success return the sensor name for the sensor.
90 */
nameProperty(const Info & sensorInfo)91 inline SensorName nameProperty(const Info& sensorInfo)
92 {
93 return sensorInfo.propertyInterfaces.begin()->second.begin()->first;
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/dimm0 then
98 * the leaf dimm0 is considered as the sensor name.
99 *
100 * @param[in] sensorInfo - Dbus info related to sensor.
101 *
102 * @return On success return the sensor name for the sensor.
103 */
nameLeaf(const Info & sensorInfo)104 inline SensorName nameLeaf(const Info& sensorInfo)
105 {
106 return sensorInfo.sensorPath.substr(
107 sensorInfo.sensorPath.find_last_of('/') + 1,
108 sensorInfo.sensorPath.length());
109 }
110
111 /** @brief Populate sensor name from the D-Bus object associated with the
112 * sensor and the property.
113 * If the object path is /xyz/openbmc_project/inventory/Fan0 and
114 * the property is Present, the leaf Fan0 and the Property is
115 * joined to Fan0_Present as the sensor name.
116 *
117 * @param[in] sensorInfo - Dbus info related to sensor.
118 *
119 * @return On success return the sensor name for the sensor.
120 */
nameLeafProperty(const Info & sensorInfo)121 inline SensorName nameLeafProperty(const Info& sensorInfo)
122 {
123 return nameLeaf(sensorInfo) + "_" + nameProperty(sensorInfo);
124 }
125
126 /** @brief Populate sensor name from the D-Bus object associated with the
127 * sensor. If the object path is /system/chassis/motherboard/cpu0/core0
128 * then the sensor name is cpu0_core0. The leaf and the parent is put
129 * together to get the sensor name.
130 *
131 * @param[in] sensorInfo - Dbus info related to sensor.
132 *
133 * @return On success return the sensor name for the sensor.
134 */
135 SensorName nameParentLeaf(const Info& sensorInfo);
136
137 /**
138 * @brief Helper function to map the dbus info to sensor's assertion status
139 * for the get sensor reading command.
140 *
141 * @param[in] sensorInfo - Dbus info related to sensor.
142 * @param[in] path - Dbus object path.
143 * @param[in] interface - Dbus interface.
144 *
145 * @return Response for get sensor reading command.
146 */
147 GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
148 const InstancePath& path,
149 const DbusInterface& interface);
150
151 #ifndef FEATURE_SENSORS_CACHE
152 /**
153 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
154 * reading command response.
155 *
156 * @param[in] sensorInfo - Dbus info related to sensor.
157 *
158 * @return Response for get sensor reading command.
159 */
160 GetSensorResponse assertion(const Info& sensorInfo);
161
162 /**
163 * @brief Maps the Dbus info to the reading field in the Get sensor reading
164 * command response.
165 *
166 * @param[in] sensorInfo - Dbus info related to sensor.
167 *
168 * @return Response for get sensor reading command.
169 */
170 GetSensorResponse eventdata2(const Info& sensorInfo);
171
172 /**
173 * @brief readingAssertion is a case where the entire assertion state field
174 * serves as the sensor value.
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>
readingAssertion(const Info & sensorInfo)182 GetSensorResponse readingAssertion(const Info& sensorInfo)
183 {
184 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
185 GetSensorResponse response{};
186
187 enableScanning(response);
188 try
189 {
190 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
191 sensorInfo.sensorPath);
192 auto propValue = ipmi::getDbusProperty(
193 bus, service, sensorInfo.sensorPath,
194 sensorInfo.propertyInterfaces.begin()->first,
195 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
196
197 setAssertionBytes(static_cast<uint16_t>(std::get<T>(propValue)),
198 response);
199 }
200 catch (const std::exception& e)
201 {
202 lg2::error(
203 "Failed to call readingAssertion, path: {PATH}, interface: {INTERFACE}: {ERROR}",
204 "PATH", sensorInfo.sensorPath, "INTERFACE",
205 sensorInfo.sensorInterface, "ERROR", e);
206 }
207
208 return response;
209 }
210
211 /** @brief Map the Dbus info to the reading field in the Get sensor reading
212 * command response
213 *
214 * @tparam T - type of the dbus property related to sensor.
215 * @param[in] sensorInfo - Dbus info related to sensor.
216 *
217 * @return Response for get sensor reading command.
218 */
219 template <typename T>
readingData(const Info & sensorInfo)220 GetSensorResponse readingData(const Info& sensorInfo)
221 {
222 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
223
224 GetSensorResponse response{};
225
226 enableScanning(response);
227
228 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
229 sensorInfo.sensorPath);
230
231 #ifdef UPDATE_FUNCTIONAL_ON_FAIL
232 // Check the OperationalStatus interface for functional property
233 if (sensorInfo.propertyInterfaces.begin()->first == SensorValue::interface)
234 {
235 bool functional = true;
236 try
237 {
238 auto funcValue = ipmi::getDbusProperty(
239 bus, service, sensorInfo.sensorPath,
240 "xyz.openbmc_project.State.Decorator.OperationalStatus",
241 "Functional");
242 functional = std::get<bool>(funcValue);
243 }
244 catch (...)
245 {
246 // No-op if Functional property could not be found since this
247 // check is only valid for Sensor.Value read for hwmonio
248 }
249 if (!functional)
250 {
251 throw SensorFunctionalError();
252 }
253 }
254 #endif
255
256 double value{};
257 try
258 {
259 auto propValue = ipmi::getDbusProperty(
260 bus, service, sensorInfo.sensorPath,
261 sensorInfo.propertyInterfaces.begin()->first,
262 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
263
264 value = std::get<T>(propValue) *
265 std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
266 }
267 catch (const std::exception& e)
268 {
269 lg2::error(
270 "Failed to call readingData, path: {PATH}, interface: {INTERFACE}: {ERROR}",
271 "PATH", sensorInfo.sensorPath, "INTERFACE",
272 sensorInfo.sensorInterface, "ERROR", e);
273 return response;
274 }
275
276 int32_t rawData =
277 (value - sensorInfo.scaledOffset) / sensorInfo.coefficientM;
278 constexpr uint8_t reserved_bits_7_6 = 0xC0; // bits[7:6] = 11b (reserved)
279 constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
280 constexpr uint8_t signedDataFormat = 0x80;
281 // if sensorUnits1 [7:6] = 10b, sensor is signed
282 int32_t minClamp;
283 int32_t maxClamp;
284 if ((sensorInfo.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
285 {
286 minClamp = std::numeric_limits<int8_t>::lowest();
287 maxClamp = std::numeric_limits<int8_t>::max();
288 }
289 else
290 {
291 minClamp = std::numeric_limits<uint8_t>::lowest();
292 maxClamp = std::numeric_limits<uint8_t>::max();
293 }
294 setReading(static_cast<uint8_t>(std::clamp(rawData, minClamp, maxClamp)),
295 response);
296
297 if (!std::isfinite(value))
298 {
299 response.readingOrStateUnavailable = 1;
300 }
301
302 bool critAlarmHigh;
303 try
304 {
305 critAlarmHigh = std::get<bool>(ipmi::getDbusProperty(
306 bus, service, sensorInfo.sensorPath,
307 SensorThresholdCritical::interface,
308 SensorThresholdCritical::property_names::critical_alarm_high));
309 }
310 catch (const std::exception& e)
311 {
312 critAlarmHigh = false;
313 }
314 bool critAlarmLow;
315 try
316 {
317 critAlarmLow = std::get<bool>(ipmi::getDbusProperty(
318 bus, service, sensorInfo.sensorPath,
319 SensorThresholdCritical::interface,
320 SensorThresholdCritical::property_names::critical_alarm_low));
321 }
322 catch (const std::exception& e)
323 {
324 critAlarmLow = false;
325 }
326 bool warningAlarmHigh;
327 try
328 {
329 warningAlarmHigh = std::get<bool>(ipmi::getDbusProperty(
330 bus, service, sensorInfo.sensorPath,
331 SensorThresholdWarning::interface,
332 SensorThresholdWarning::property_names::warning_alarm_high));
333 }
334 catch (const std::exception& e)
335 {
336 warningAlarmHigh = false;
337 }
338 bool warningAlarmLow;
339 try
340 {
341 warningAlarmLow = std::get<bool>(ipmi::getDbusProperty(
342 bus, service, sensorInfo.sensorPath,
343 SensorThresholdWarning::interface,
344 SensorThresholdWarning::property_names::warning_alarm_low));
345 }
346 catch (const std::exception& e)
347 {
348 warningAlarmLow = false;
349 }
350 response.thresholdLevelsStates =
351 reserved_bits_7_6 | (static_cast<uint8_t>(critAlarmHigh) << 4) |
352 (static_cast<uint8_t>(warningAlarmHigh) << 3) |
353 (static_cast<uint8_t>(critAlarmLow) << 1) |
354 (static_cast<uint8_t>(warningAlarmLow) << 0);
355 return response;
356 }
357 #else
358
359 /**
360 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
361 * reading command response.
362 *
363 * @param[in] id - The sensor id
364 * @param[in] sensorInfo - Dbus info related to sensor.
365 * @param[in] msg - Dbus message from match callback.
366 *
367 * @return Response for get sensor reading command.
368 */
369 std::optional<GetSensorResponse> assertion(uint8_t id, const Info& sensorInfo,
370 const PropertyMap& properties);
371
372 /**
373 * @brief Maps the Dbus info to the reading field in the Get sensor reading
374 * command response.
375 *
376 * @param[in] id - The sensor id
377 * @param[in] sensorInfo - Dbus info related to sensor.
378 * @param[in] msg - Dbus message from match callback.
379 *
380 * @return Response for get sensor reading command.
381 */
382 std::optional<GetSensorResponse> eventdata2(uint8_t id, const Info& sensorInfo,
383 const PropertyMap& properties);
384
385 /**
386 * @brief readingAssertion is a case where the entire assertion state field
387 * serves as the sensor value.
388 *
389 * @tparam T - type of the dbus property related to sensor.
390 * @param[in] id - The sensor id
391 * @param[in] sensorInfo - Dbus info related to sensor.
392 * @param[in] msg - Dbus message from match callback.
393 *
394 * @return Response for get sensor reading command.
395 */
396 template <typename T>
readingAssertion(uint8_t id,const Info & sensorInfo,const PropertyMap & properties)397 std::optional<GetSensorResponse> readingAssertion(
398 uint8_t id, const Info& sensorInfo, const PropertyMap& properties)
399 {
400 GetSensorResponse response{};
401 enableScanning(response);
402
403 auto iter = properties.find(
404 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
405 if (iter == properties.end())
406 {
407 return {};
408 }
409
410 setAssertionBytes(static_cast<uint16_t>(std::get<T>(iter->second)),
411 response);
412
413 if (!sensorCacheMap[id].has_value())
414 {
415 sensorCacheMap[id] = SensorData{};
416 }
417 sensorCacheMap[id]->response = response;
418 return response;
419 }
420
421 /** @brief Get sensor reading from the dbus message from match
422 *
423 * @tparam T - type of the dbus property related to sensor.
424 * @param[in] id - The sensor id
425 * @param[in] sensorInfo - Dbus info related to sensor.
426 * @param[in] msg - Dbus message from match callback.
427 *
428 * @return Response for get sensor reading command.
429 */
430 template <typename T>
readingData(uint8_t id,const Info & sensorInfo,const PropertyMap & properties)431 std::optional<GetSensorResponse> readingData(uint8_t id, const Info& sensorInfo,
432 const PropertyMap& properties)
433 {
434 auto iter = properties.find("Functional");
435 if (iter != properties.end())
436 {
437 sensorCacheMap[id]->functional = std::get<bool>(iter->second);
438 }
439 iter = properties.find("Available");
440 if (iter != properties.end())
441 {
442 sensorCacheMap[id]->available = std::get<bool>(iter->second);
443 }
444 #ifdef UPDATE_FUNCTIONAL_ON_FAIL
445 if (sensorCacheMap[id])
446 {
447 if (!sensorCacheMap[id]->functional)
448 {
449 throw SensorFunctionalError();
450 }
451 }
452 #endif
453
454 GetSensorResponse response{};
455
456 enableScanning(response);
457
458 iter = properties.find(
459 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
460 if (iter == properties.end())
461 {
462 return {};
463 }
464
465 double value = std::get<T>(iter->second) *
466 std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
467 int32_t rawData =
468 (value - sensorInfo.scaledOffset) / sensorInfo.coefficientM;
469
470 constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
471 constexpr uint8_t signedDataFormat = 0x80;
472 // if sensorUnits1 [7:6] = 10b, sensor is signed
473 if ((sensorInfo.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
474 {
475 if (rawData > std::numeric_limits<int8_t>::max() ||
476 rawData < std::numeric_limits<int8_t>::lowest())
477 {
478 lg2::error("Value out of range");
479 throw std::out_of_range("Value out of range");
480 }
481 setReading(static_cast<int8_t>(rawData), response);
482 }
483 else
484 {
485 if (rawData > std::numeric_limits<uint8_t>::max() ||
486 rawData < std::numeric_limits<uint8_t>::lowest())
487 {
488 lg2::error("Value out of range");
489 throw std::out_of_range("Value out of range");
490 }
491 setReading(static_cast<uint8_t>(rawData), response);
492 }
493
494 if (!std::isfinite(value))
495 {
496 response.readingOrStateUnavailable = 1;
497 }
498
499 if (!sensorCacheMap[id].has_value())
500 {
501 sensorCacheMap[id] = SensorData{};
502 }
503 sensorCacheMap[id]->response = response;
504
505 return response;
506 }
507
508 #endif // FEATURE_SENSORS_CACHE
509
510 } // namespace get
511
512 namespace set
513 {
514
515 /** @brief Make a DBus message for a Dbus call
516 * @param[in] updateInterface - Interface name
517 * @param[in] sensorPath - Path of the sensor
518 * @param[in] command - command to be executed
519 * @param[in] sensorInterface - DBus interface of sensor
520 * @return a dbus message
521 */
522 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
523 const std::string& sensorPath,
524 const std::string& command,
525 const std::string& sensorInterface);
526
527 /** @brief Update d-bus based on assertion type sensor data
528 * @param[in] cmdData - input sensor data
529 * @param[in] sensorInfo - sensor d-bus info
530 * @return a IPMI error code
531 */
532 ipmi::Cc assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo);
533
534 /** @brief Update d-bus based on a reading assertion
535 * @tparam T - type of d-bus property mapping this sensor
536 * @param[in] cmdData - input sensor data
537 * @param[in] sensorInfo - sensor d-bus info
538 * @return a IPMI error code
539 */
540 template <typename T>
readingAssertion(const SetSensorReadingReq & cmdData,const Info & sensorInfo)541 ipmi::Cc readingAssertion(const SetSensorReadingReq& cmdData,
542 const Info& sensorInfo)
543 {
544 auto msg =
545 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
546 "Set", sensorInfo.sensorInterface);
547
548 const auto& interface = sensorInfo.propertyInterfaces.begin();
549 msg.append(interface->first);
550 for (const auto& property : interface->second)
551 {
552 msg.append(property.first);
553 std::variant<T> value = static_cast<T>(
554 (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7);
555 msg.append(value);
556 }
557 return updateToDbus(msg);
558 }
559
560 /** @brief Update d-bus based on a discrete reading
561 * @param[in] cmdData - input sensor data
562 * @param[in] sensorInfo - sensor d-bus info
563 * @return an IPMI error code
564 */
565 template <typename T>
readingData(const SetSensorReadingReq & cmdData,const Info & sensorInfo)566 ipmi::Cc readingData(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
567 {
568 T raw_value = (sensorInfo.coefficientM * cmdData.reading) +
569 sensorInfo.scaledOffset;
570
571 raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale);
572
573 auto msg =
574 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
575 "Set", sensorInfo.sensorInterface);
576
577 const auto& interface = sensorInfo.propertyInterfaces.begin();
578 msg.append(interface->first);
579
580 for (const auto& property : interface->second)
581 {
582 msg.append(property.first);
583 std::variant<T> value = raw_value;
584 msg.append(value);
585 }
586 return updateToDbus(msg);
587 }
588
589 /** @brief Update d-bus based on eventdata type sensor data
590 * @param[in] cmdData - input sensor data
591 * @param[in] sensorInfo - sensor d-bus info
592 * @return a IPMI error code
593 */
594 ipmi::Cc eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
595 uint8_t data);
596
597 /** @brief Update d-bus based on eventdata1 type sensor data
598 * @param[in] cmdData - input sensor data
599 * @param[in] sensorInfo - sensor d-bus info
600 * @return a IPMI error code
601 */
eventdata1(const SetSensorReadingReq & cmdData,const Info & sensorInfo)602 inline ipmi::Cc eventdata1(const SetSensorReadingReq& cmdData,
603 const Info& sensorInfo)
604 {
605 return eventdata(cmdData, sensorInfo, cmdData.eventData1);
606 }
607
608 /** @brief Update d-bus based on eventdata2 type sensor data
609 * @param[in] cmdData - input sensor data
610 * @param[in] sensorInfo - sensor d-bus info
611 * @return a IPMI error code
612 */
eventdata2(const SetSensorReadingReq & cmdData,const Info & sensorInfo)613 inline ipmi::Cc eventdata2(const SetSensorReadingReq& cmdData,
614 const Info& sensorInfo)
615 {
616 return eventdata(cmdData, sensorInfo, cmdData.eventData2);
617 }
618
619 /** @brief Update d-bus based on eventdata3 type sensor data
620 * @param[in] cmdData - input sensor data
621 * @param[in] sensorInfo - sensor d-bus info
622 * @return a IPMI error code
623 */
eventdata3(const SetSensorReadingReq & cmdData,const Info & sensorInfo)624 inline ipmi::Cc eventdata3(const SetSensorReadingReq& cmdData,
625 const Info& sensorInfo)
626 {
627 return eventdata(cmdData, sensorInfo, cmdData.eventData3);
628 }
629
630 } // namespace set
631
632 namespace notify
633 {
634
635 /** @brief Make a DBus message for a Dbus call
636 * @param[in] updateInterface - Interface name
637 * @param[in] sensorPath - Path of the sensor
638 * @param[in] command - command to be executed
639 * @param[in] sensorInterface - DBus interface of sensor
640 * @return a dbus message
641 */
642 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
643 const std::string& sensorPath,
644 const std::string& command,
645 const std::string& sensorInterface);
646
647 /** @brief Update d-bus based on assertion type sensor data
648 * @param[in] interfaceMap - sensor interface
649 * @param[in] cmdData - input sensor data
650 * @param[in] sensorInfo - sensor d-bus info
651 * @return a IPMI error code
652 */
653 ipmi::Cc assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo);
654
655 } // namespace notify
656
657 namespace inventory
658 {
659
660 namespace get
661 {
662
663 #ifndef FEATURE_SENSORS_CACHE
664
665 /**
666 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
667 * reading command response.
668 *
669 * @param[in] sensorInfo - Dbus info related to sensor.
670 *
671 * @return Response for get sensor reading command.
672 */
673 GetSensorResponse assertion(const Info& sensorInfo);
674
675 #else
676
677 /**
678 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
679 * reading command response.
680 *
681 * @param[in] id - The sensor id
682 * @param[in] sensorInfo - Dbus info related to sensor.
683 * @param[in] msg - Dbus message from match callback.
684 *
685 * @return Response for get sensor reading command.
686 */
687 std::optional<GetSensorResponse> assertion(uint8_t id, const Info& sensorInfo,
688 const PropertyMap& properties);
689
690 #endif
691
692 } // namespace get
693
694 } // namespace inventory
695 } // namespace sensor
696 } // namespace ipmi
697