1 #pragma once
2 
3 #include <stdint.h>
4 
5 #include <ipmid/api.hpp>
6 #include <ipmid/types.hpp>
7 
8 #include <exception>
9 
10 // IPMI commands for net functions.
11 enum ipmi_netfn_sen_cmds
12 {
13     IPMI_CMD_PLATFORM_EVENT = 0x2,
14     IPMI_CMD_GET_DEVICE_SDR_INFO = 0x20,
15     IPMI_CMD_GET_DEVICE_SDR = 0x21,
16     IPMI_CMD_RESERVE_DEVICE_SDR_REPO = 0x22,
17     IPMI_CMD_GET_SENSOR_READING = 0x2D,
18     IPMI_CMD_GET_SENSOR_TYPE = 0x2F,
19     IPMI_CMD_SET_SENSOR = 0x30,
20     IPMI_CMD_GET_SENSOR_THRESHOLDS = 0x27,
21 };
22 
23 /**
24  * @enum device_type
25  * IPMI FRU device types
26  */
27 enum device_type
28 {
29     IPMI_PHYSICAL_FRU = 0x00,
30     IPMI_LOGICAL_FRU = 0x80,
31 };
32 
33 // Discrete sensor types.
34 enum ipmi_sensor_types
35 {
36     IPMI_SENSOR_TEMP = 0x01,
37     IPMI_SENSOR_VOLTAGE = 0x02,
38     IPMI_SENSOR_CURRENT = 0x03,
39     IPMI_SENSOR_FAN = 0x04,
40     IPMI_SENSOR_TPM = 0xCC,
41 };
42 
43 /** @brief Custom exception for reading sensors that are not funcitonal.
44  */
45 struct SensorFunctionalError : public std::exception
46 {
47     const char* what() const noexcept
48     {
49         return "Sensor not functional";
50     }
51 };
52 
53 #define MAX_DBUS_PATH 128
54 struct dbus_interface_t
55 {
56     uint8_t sensornumber;
57     uint8_t sensortype;
58 
59     char bus[MAX_DBUS_PATH];
60     char path[MAX_DBUS_PATH];
61     char interface[MAX_DBUS_PATH];
62 };
63 
64 struct PlatformEventRequest
65 {
66     uint8_t eventMessageRevision;
67     uint8_t sensorType;
68     uint8_t sensorNumber;
69     uint8_t eventDirectionType;
70     uint8_t data[3];
71 };
72 
73 static constexpr const char* ipmiSELPath = "/xyz/openbmc_project/Logging/IPMI";
74 static constexpr const char* ipmiSELAddInterface =
75     "xyz.openbmc_project.Logging.IPMI";
76 static const std::string ipmiSELAddMessage = "IPMI generated SEL Entry";
77 
78 static constexpr int selSystemEventSizeWith3Bytes = 8;
79 static constexpr int selSystemEventSizeWith2Bytes = 7;
80 static constexpr int selSystemEventSizeWith1Bytes = 6;
81 static constexpr int selIPMBEventSize = 7;
82 static constexpr uint8_t directionMask = 0x80;
83 static constexpr uint8_t byte3EnableMask = 0x30;
84 static constexpr uint8_t byte2EnableMask = 0xC0;
85 
86 int set_sensor_dbus_state_s(uint8_t, const char*, const char*);
87 int set_sensor_dbus_state_y(uint8_t, const char*, const uint8_t);
88 int find_openbmc_path(uint8_t, dbus_interface_t*);
89 
90 ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
91                             ipmi_request_t request, ipmi_response_t response,
92                             ipmi_data_len_t data_len, ipmi_context_t context);
93 
94 ipmi::RspType<uint16_t> ipmiSensorReserveSdr();
95 
96 static const uint16_t FRU_RECORD_ID_START = 256;
97 static const uint16_t ENTITY_RECORD_ID_START = 512;
98 static const uint8_t SDR_VERSION = 0x51;
99 static const uint16_t END_OF_RECORD = 0xFFFF;
100 static const uint8_t LENGTH_MASK = 0x1F;
101 
102 /**
103  * Get SDR Info
104  */
105 
106 namespace get_sdr_info
107 {
108 namespace request
109 {
110 // Note: for some reason the ipmi_request_t appears to be the
111 // raw value for this call.
112 inline bool get_count(void* req)
113 {
114     return (bool)((uint64_t)(req) & 1);
115 }
116 } // namespace request
117 } // namespace get_sdr_info
118 
119 /**
120  * Get SDR
121  */
122 namespace get_sdr
123 {
124 
125 struct GetSdrReq
126 {
127     uint8_t reservation_id_lsb;
128     uint8_t reservation_id_msb;
129     uint8_t record_id_lsb;
130     uint8_t record_id_msb;
131     uint8_t offset;
132     uint8_t bytes_to_read;
133 } __attribute__((packed));
134 
135 namespace request
136 {
137 
138 inline uint16_t get_reservation_id(GetSdrReq* req)
139 {
140     return (req->reservation_id_lsb + (req->reservation_id_msb << 8));
141 };
142 
143 inline uint16_t get_record_id(GetSdrReq* req)
144 {
145     return (req->record_id_lsb + (req->record_id_msb << 8));
146 };
147 
148 } // namespace request
149 
150 // Response
151 struct GetSdrResp
152 {
153     uint8_t next_record_id_lsb;
154     uint8_t next_record_id_msb;
155     uint8_t record_data[64];
156 } __attribute__((packed));
157 
158 namespace response
159 {
160 
161 inline void set_next_record_id(uint16_t next, GetSdrResp* resp)
162 {
163     resp->next_record_id_lsb = next & 0xff;
164     resp->next_record_id_msb = (next >> 8) & 0xff;
165 };
166 
167 } // namespace response
168 
169 // Record header
170 struct SensorDataRecordHeader
171 {
172     uint8_t record_id_lsb;
173     uint8_t record_id_msb;
174     uint8_t sdr_version;
175     uint8_t record_type;
176     uint8_t record_length; // Length not counting the header
177 } __attribute__((packed));
178 
179 namespace header
180 {
181 
182 inline void set_record_id(int id, SensorDataRecordHeader* hdr)
183 {
184     hdr->record_id_lsb = (id & 0xFF);
185     hdr->record_id_msb = (id >> 8) & 0xFF;
186 };
187 
188 } // namespace header
189 
190 enum SensorDataRecordType
191 {
192     SENSOR_DATA_FULL_RECORD = 0x1,
193     SENSOR_DATA_COMPACT_RECORD = 0x2,
194     SENSOR_DATA_EVENT_RECORD = 0x3,
195     SENSOR_DATA_ENTITY_RECORD = 0x8,
196     SENSOR_DATA_FRU_RECORD = 0x11,
197     SENSOR_DATA_MGMT_CTRL_LOCATOR = 0x12,
198 };
199 
200 // Record key
201 struct SensorDataRecordKey
202 {
203     uint8_t owner_id;
204     uint8_t owner_lun;
205     uint8_t sensor_number;
206 } __attribute__((packed));
207 
208 /** @struct SensorDataFruRecordKey
209  *
210  *  FRU Device Locator Record(key) - SDR Type 11
211  */
212 struct SensorDataFruRecordKey
213 {
214     uint8_t deviceAddress;
215     uint8_t fruID;
216     uint8_t accessLun;
217     uint8_t channelNumber;
218 } __attribute__((packed));
219 
220 /** @struct SensorDataEntityRecordKey
221  *
222  *  Entity Association Record(key) - SDR Type 8
223  */
224 struct SensorDataEntityRecordKey
225 {
226     uint8_t containerEntityId;
227     uint8_t containerEntityInstance;
228     uint8_t flags;
229     uint8_t entityId1;
230     uint8_t entityInstance1;
231 } __attribute__((packed));
232 
233 namespace key
234 {
235 
236 static constexpr uint8_t listOrRangeBit = 7;
237 static constexpr uint8_t linkedBit = 6;
238 
239 inline void set_owner_id_ipmb(SensorDataRecordKey* key)
240 {
241     key->owner_id &= ~0x01;
242 };
243 
244 inline void set_owner_id_system_sw(SensorDataRecordKey* key)
245 {
246     key->owner_id |= 0x01;
247 };
248 
249 inline void set_owner_id_bmc(SensorDataRecordKey* key)
250 {
251     key->owner_id |= 0x20;
252 };
253 
254 inline void set_owner_id_address(uint8_t addr, SensorDataRecordKey* key)
255 {
256     key->owner_id &= 0x01;
257     key->owner_id |= addr << 1;
258 };
259 
260 inline void set_owner_lun(uint8_t lun, SensorDataRecordKey* key)
261 {
262     key->owner_lun &= ~0x03;
263     key->owner_lun |= (lun & 0x03);
264 };
265 
266 inline void set_owner_lun_channel(uint8_t channel, SensorDataRecordKey* key)
267 {
268     key->owner_lun &= 0x0f;
269     key->owner_lun |= ((channel & 0xf) << 4);
270 };
271 
272 inline void set_flags(bool isList, bool isLinked,
273                       SensorDataEntityRecordKey* key)
274 {
275     key->flags = 0x00;
276     if (!isList)
277         key->flags |= 1 << listOrRangeBit;
278 
279     if (isLinked)
280         key->flags |= 1 << linkedBit;
281 };
282 
283 } // namespace key
284 
285 /** @struct GetSensorThresholdsResponse
286  *
287  *  Response structure for Get Sensor Thresholds command
288  */
289 struct GetSensorThresholdsResponse
290 {
291     uint8_t validMask;           //!< valid mask
292     uint8_t lowerNonCritical;    //!< lower non-critical threshold
293     uint8_t lowerCritical;       //!< lower critical threshold
294     uint8_t lowerNonRecoverable; //!< lower non-recoverable threshold
295     uint8_t upperNonCritical;    //!< upper non-critical threshold
296     uint8_t upperCritical;       //!< upper critical threshold
297     uint8_t upperNonRecoverable; //!< upper non-recoverable threshold
298 } __attribute__((packed));
299 
300 // Body - full record
301 #define FULL_RECORD_ID_STR_MAX_LENGTH 16
302 
303 static const int FRU_RECORD_DEVICE_ID_MAX_LENGTH = 16;
304 
305 struct SensorDataFullRecordBody
306 {
307     uint8_t entity_id;
308     uint8_t entity_instance;
309     uint8_t sensor_initialization;
310     uint8_t sensor_capabilities; // no macro support
311     uint8_t sensor_type;
312     uint8_t event_reading_type;
313     uint8_t supported_assertions[2];          // no macro support
314     uint8_t supported_deassertions[2];        // no macro support
315     uint8_t discrete_reading_setting_mask[2]; // no macro support
316     uint8_t sensor_units_1;
317     uint8_t sensor_units_2_base;
318     uint8_t sensor_units_3_modifier;
319     uint8_t linearization;
320     uint8_t m_lsb;
321     uint8_t m_msb_and_tolerance;
322     uint8_t b_lsb;
323     uint8_t b_msb_and_accuracy_lsb;
324     uint8_t accuracy_and_sensor_direction;
325     uint8_t r_b_exponents;
326     uint8_t analog_characteristic_flags; // no macro support
327     uint8_t nominal_reading;
328     uint8_t normal_max;
329     uint8_t normal_min;
330     uint8_t sensor_max;
331     uint8_t sensor_min;
332     uint8_t upper_nonrecoverable_threshold;
333     uint8_t upper_critical_threshold;
334     uint8_t upper_noncritical_threshold;
335     uint8_t lower_nonrecoverable_threshold;
336     uint8_t lower_critical_threshold;
337     uint8_t lower_noncritical_threshold;
338     uint8_t positive_threshold_hysteresis;
339     uint8_t negative_threshold_hysteresis;
340     uint16_t reserved;
341     uint8_t oem_reserved;
342     uint8_t id_string_info;
343     char id_string[FULL_RECORD_ID_STR_MAX_LENGTH];
344 } __attribute__((packed));
345 
346 /** @struct SensorDataCompactRecord
347  *
348  *  Compact Sensor Record(body) - SDR Type 2
349  */
350 struct SensorDataCompactRecordBody
351 {
352     uint8_t entity_id;
353     uint8_t entity_instance;
354     uint8_t sensor_initialization;
355     uint8_t sensor_capabilities; // no macro support
356     uint8_t sensor_type;
357     uint8_t event_reading_type;
358     uint8_t supported_assertions[2];          // no macro support
359     uint8_t supported_deassertions[2];        // no macro support
360     uint8_t discrete_reading_setting_mask[2]; // no macro support
361     uint8_t sensor_units_1;
362     uint8_t sensor_units_2_base;
363     uint8_t sensor_units_3_modifier;
364     uint8_t record_sharing[2];
365     uint8_t positive_threshold_hysteresis;
366     uint8_t negative_threshold_hysteresis;
367     uint8_t reserved[3];
368     uint8_t oem_reserved;
369     uint8_t id_string_info;
370     char id_string[FULL_RECORD_ID_STR_MAX_LENGTH];
371 } __attribute__((packed));
372 
373 /** @struct SensorDataEventRecord
374  *
375  *  Event Only Sensor Record(body) - SDR Type 3
376  */
377 struct SensorDataEventRecordBody
378 {
379     uint8_t entity_id;
380     uint8_t entity_instance;
381     uint8_t sensor_type;
382     uint8_t event_reading_type;
383     uint8_t sensor_record_sharing_1;
384     uint8_t sensor_record_sharing_2;
385     uint8_t reserved;
386     uint8_t oem_reserved;
387     uint8_t id_string_info;
388     char id_string[FULL_RECORD_ID_STR_MAX_LENGTH];
389 } __attribute__((packed));
390 
391 /** @struct SensorDataFruRecordBody
392  *
393  *  FRU Device Locator Record(body) - SDR Type 11
394  */
395 struct SensorDataFruRecordBody
396 {
397     uint8_t reserved;
398     uint8_t deviceType;
399     uint8_t deviceTypeModifier;
400     uint8_t entityID;
401     uint8_t entityInstance;
402     uint8_t oem;
403     uint8_t deviceIDLen;
404     char deviceID[FRU_RECORD_DEVICE_ID_MAX_LENGTH];
405 } __attribute__((packed));
406 
407 /** @struct SensorDataEntityRecordBody
408  *
409  *  Entity Association Record(body) - SDR Type 8
410  */
411 struct SensorDataEntityRecordBody
412 {
413     uint8_t entityId2;
414     uint8_t entityInstance2;
415     uint8_t entityId3;
416     uint8_t entityInstance3;
417     uint8_t entityId4;
418     uint8_t entityInstance4;
419 } __attribute__((packed));
420 
421 namespace body
422 {
423 
424 inline void set_entity_instance_number(uint8_t n,
425                                        SensorDataFullRecordBody* body)
426 {
427     body->entity_instance &= 1 << 7;
428     body->entity_instance |= (n & ~(1 << 7));
429 };
430 inline void set_entity_physical_entity(SensorDataFullRecordBody* body)
431 {
432     body->entity_instance &= ~(1 << 7);
433 };
434 inline void set_entity_logical_container(SensorDataFullRecordBody* body)
435 {
436     body->entity_instance |= 1 << 7;
437 };
438 
439 inline void sensor_scanning_state(bool enabled, SensorDataFullRecordBody* body)
440 {
441     if (enabled)
442     {
443         body->sensor_initialization |= 1 << 0;
444     }
445     else
446     {
447         body->sensor_initialization &= ~(1 << 0);
448     };
449 };
450 inline void event_generation_state(bool enabled, SensorDataFullRecordBody* body)
451 {
452     if (enabled)
453     {
454         body->sensor_initialization |= 1 << 1;
455     }
456     else
457     {
458         body->sensor_initialization &= ~(1 << 1);
459     }
460 };
461 inline void init_types_state(bool enabled, SensorDataFullRecordBody* body)
462 {
463     if (enabled)
464     {
465         body->sensor_initialization |= 1 << 2;
466     }
467     else
468     {
469         body->sensor_initialization &= ~(1 << 2);
470     }
471 };
472 inline void init_hyst_state(bool enabled, SensorDataFullRecordBody* body)
473 {
474     if (enabled)
475     {
476         body->sensor_initialization |= 1 << 3;
477     }
478     else
479     {
480         body->sensor_initialization &= ~(1 << 3);
481     }
482 };
483 inline void init_thresh_state(bool enabled, SensorDataFullRecordBody* body)
484 {
485     if (enabled)
486     {
487         body->sensor_initialization |= 1 << 4;
488     }
489     else
490     {
491         body->sensor_initialization &= ~(1 << 4);
492     }
493 };
494 inline void init_events_state(bool enabled, SensorDataFullRecordBody* body)
495 {
496     if (enabled)
497     {
498         body->sensor_initialization |= 1 << 5;
499     }
500     else
501     {
502         body->sensor_initialization &= ~(1 << 5);
503     }
504 };
505 inline void init_scanning_state(bool enabled, SensorDataFullRecordBody* body)
506 {
507     if (enabled)
508     {
509         body->sensor_initialization |= 1 << 6;
510     }
511     else
512     {
513         body->sensor_initialization &= ~(1 << 6);
514     }
515 };
516 inline void init_settable_state(bool enabled, SensorDataFullRecordBody* body)
517 {
518     if (enabled)
519     {
520         body->sensor_initialization |= 1 << 7;
521     }
522     else
523     {
524         body->sensor_initialization &= ~(1 << 7);
525     }
526 };
527 
528 inline void set_percentage(SensorDataFullRecordBody* body)
529 {
530     body->sensor_units_1 |= 1 << 0;
531 };
532 inline void unset_percentage(SensorDataFullRecordBody* body)
533 {
534     body->sensor_units_1 &= ~(1 << 0);
535 };
536 inline void set_modifier_operation(uint8_t op, SensorDataFullRecordBody* body)
537 {
538     body->sensor_units_1 &= ~(3 << 1);
539     body->sensor_units_1 |= (op & 0x3) << 1;
540 };
541 inline void set_rate_unit(uint8_t unit, SensorDataFullRecordBody* body)
542 {
543     body->sensor_units_1 &= ~(7 << 3);
544     body->sensor_units_1 |= (unit & 0x7) << 3;
545 };
546 inline void set_analog_data_format(uint8_t format,
547                                    SensorDataFullRecordBody* body)
548 {
549     body->sensor_units_1 &= ~(3 << 6);
550     body->sensor_units_1 |= (format & 0x3) << 6;
551 };
552 
553 inline void set_m(uint16_t m, SensorDataFullRecordBody* body)
554 {
555     body->m_lsb = m & 0xff;
556     body->m_msb_and_tolerance &= ~(3 << 6);
557     body->m_msb_and_tolerance |= ((m & (3 << 8)) >> 2);
558 };
559 inline void set_tolerance(uint8_t tol, SensorDataFullRecordBody* body)
560 {
561     body->m_msb_and_tolerance &= ~0x3f;
562     body->m_msb_and_tolerance |= tol & 0x3f;
563 };
564 
565 inline void set_b(uint16_t b, SensorDataFullRecordBody* body)
566 {
567     body->b_lsb = b & 0xff;
568     body->b_msb_and_accuracy_lsb &= ~(3 << 6);
569     body->b_msb_and_accuracy_lsb |= ((b & (3 << 8)) >> 2);
570 };
571 inline void set_accuracy(uint16_t acc, SensorDataFullRecordBody* body)
572 {
573     // bottom 6 bits
574     body->b_msb_and_accuracy_lsb &= ~0x3f;
575     body->b_msb_and_accuracy_lsb |= acc & 0x3f;
576     // top 4 bits
577     body->accuracy_and_sensor_direction &= 0x0f;
578     body->accuracy_and_sensor_direction |= ((acc >> 6) & 0xf) << 4;
579 };
580 inline void set_accuracy_exp(uint8_t exp, SensorDataFullRecordBody* body)
581 {
582     body->accuracy_and_sensor_direction &= ~(3 << 2);
583     body->accuracy_and_sensor_direction |= (exp & 3) << 2;
584 };
585 inline void set_sensor_dir(uint8_t dir, SensorDataFullRecordBody* body)
586 {
587     body->accuracy_and_sensor_direction &= ~(3 << 0);
588     body->accuracy_and_sensor_direction |= (dir & 3);
589 };
590 
591 inline void set_b_exp(uint8_t exp, SensorDataFullRecordBody* body)
592 {
593     body->r_b_exponents &= 0xf0;
594     body->r_b_exponents |= exp & 0x0f;
595 };
596 inline void set_r_exp(uint8_t exp, SensorDataFullRecordBody* body)
597 {
598     body->r_b_exponents &= 0x0f;
599     body->r_b_exponents |= (exp & 0x0f) << 4;
600 };
601 
602 inline void set_id_strlen(uint8_t len, SensorDataFullRecordBody* body)
603 {
604     body->id_string_info &= ~(0x1f);
605     body->id_string_info |= len & 0x1f;
606 };
607 inline void set_id_strlen(uint8_t len, SensorDataEventRecordBody* body)
608 {
609     body->id_string_info &= ~(0x1f);
610     body->id_string_info |= len & 0x1f;
611 };
612 inline uint8_t get_id_strlen(SensorDataFullRecordBody* body)
613 {
614     return body->id_string_info & 0x1f;
615 };
616 inline void set_id_type(uint8_t type, SensorDataFullRecordBody* body)
617 {
618     body->id_string_info &= ~(3 << 6);
619     body->id_string_info |= (type & 0x3) << 6;
620 };
621 inline void set_id_type(uint8_t type, SensorDataEventRecordBody* body)
622 {
623     body->id_string_info &= ~(3 << 6);
624     body->id_string_info |= (type & 0x3) << 6;
625 };
626 
627 inline void set_device_id_strlen(uint8_t len, SensorDataFruRecordBody* body)
628 {
629     body->deviceIDLen &= ~(LENGTH_MASK);
630     body->deviceIDLen |= len & LENGTH_MASK;
631 };
632 
633 inline uint8_t get_device_id_strlen(SensorDataFruRecordBody* body)
634 {
635     return body->deviceIDLen & LENGTH_MASK;
636 };
637 
638 inline void set_readable_mask(uint8_t mask, SensorDataFullRecordBody* body)
639 {
640     body->discrete_reading_setting_mask[1] = mask & 0x3F;
641 }
642 
643 } // namespace body
644 
645 // More types contained in section 43.17 Sensor Unit Type Codes,
646 // IPMI spec v2 rev 1.1
647 enum SensorUnitTypeCodes
648 {
649     SENSOR_UNIT_UNSPECIFIED = 0,
650     SENSOR_UNIT_DEGREES_C = 1,
651     SENSOR_UNIT_VOLTS = 4,
652     SENSOR_UNIT_AMPERES = 5,
653     SENSOR_UNIT_WATTS = 6,
654     SENSOR_UNIT_JOULES = 7,
655     SENSOR_UNIT_RPM = 18,
656     SENSOR_UNIT_METERS = 34,
657     SENSOR_UNIT_REVOLUTIONS = 41,
658 };
659 
660 struct SensorDataFullRecord
661 {
662     SensorDataRecordHeader header;
663     SensorDataRecordKey key;
664     SensorDataFullRecordBody body;
665 } __attribute__((packed));
666 
667 /** @struct SensorDataComapactRecord
668  *
669  *  Compact Sensor Record - SDR Type 2
670  */
671 struct SensorDataCompactRecord
672 {
673     SensorDataRecordHeader header;
674     SensorDataRecordKey key;
675     SensorDataCompactRecordBody body;
676 } __attribute__((packed));
677 
678 /** @struct SensorDataEventRecord
679  *
680  *  Event Only Sensor Record - SDR Type 3
681  */
682 struct SensorDataEventRecord
683 {
684     SensorDataRecordHeader header;
685     SensorDataRecordKey key;
686     SensorDataEventRecordBody body;
687 } __attribute__((packed));
688 
689 /** @struct SensorDataFruRecord
690  *
691  *  FRU Device Locator Record - SDR Type 11
692  */
693 struct SensorDataFruRecord
694 {
695     SensorDataRecordHeader header;
696     SensorDataFruRecordKey key;
697     SensorDataFruRecordBody body;
698 } __attribute__((packed));
699 
700 /** @struct SensorDataEntityRecord
701  *
702  *  Entity Association Record - SDR Type 8
703  */
704 struct SensorDataEntityRecord
705 {
706     SensorDataRecordHeader header;
707     SensorDataEntityRecordKey key;
708     SensorDataEntityRecordBody body;
709 } __attribute__((packed));
710 
711 } // namespace get_sdr
712 
713 namespace ipmi
714 {
715 
716 namespace sensor
717 {
718 
719 /**
720  * @brief Map offset to the corresponding bit in the assertion byte.
721  *
722  * The discrete sensors support up to 14 states. 0-7 offsets are stored in one
723  * byte and offsets 8-14 in the second byte.
724  *
725  * @param[in] offset - offset number.
726  * @param[in/out] resp - get sensor reading response.
727  */
728 inline void setOffset(uint8_t offset, ipmi::sensor::GetSensorResponse* resp)
729 {
730     if (offset > 7)
731     {
732         resp->discreteReadingSensorStates |= 1 << (offset - 8);
733     }
734     else
735     {
736         resp->thresholdLevelsStates |= 1 << offset;
737     }
738 }
739 
740 /**
741  * @brief Set the reading field in the response.
742  *
743  * @param[in] offset - offset number.
744  * @param[in/out] resp - get sensor reading response.
745  */
746 inline void setReading(uint8_t value, ipmi::sensor::GetSensorResponse* resp)
747 {
748     resp->reading = value;
749 }
750 
751 /**
752  * @brief Map the value to the assertion bytes. The assertion states are stored
753  *        in 2 bytes.
754  *
755  * @param[in] value - value to mapped to the assertion byte.
756  * @param[in/out] resp - get sensor reading response.
757  */
758 inline void setAssertionBytes(uint16_t value,
759                               ipmi::sensor::GetSensorResponse* resp)
760 {
761     resp->thresholdLevelsStates = static_cast<uint8_t>(value & 0x00FF);
762     resp->discreteReadingSensorStates = static_cast<uint8_t>(value >> 8);
763 }
764 
765 /**
766  * @brief Set the scanning enabled bit in the response.
767  *
768  * @param[in/out] resp - get sensor reading response.
769  */
770 inline void enableScanning(ipmi::sensor::GetSensorResponse* resp)
771 {
772     resp->readingOrStateUnavailable = false;
773     resp->scanningEnabled = true;
774     resp->allEventMessagesEnabled = false;
775 }
776 
777 } // namespace sensor
778 
779 } // namespace ipmi
780