1 #pragma once
2 #include <boost/asio/steady_timer.hpp>
3 #include <boost/container/flat_map.hpp>
4 #include <sensor.hpp>
5
6 #include <chrono>
7 #include <limits>
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <vector>
12
13 constexpr const char* sensorType = "IpmbSensor";
14 constexpr const char* sdrInterface = "IpmbDevice";
15
16 enum class IpmbType
17 {
18 none,
19 meSensor,
20 PXE1410CVR,
21 IR38363VR,
22 ADM1278HSC,
23 mpsVR,
24 SMPro
25 };
26
27 enum class IpmbSubType
28 {
29 none,
30 temp,
31 curr,
32 power,
33 volt,
34 util
35 };
36
37 enum class ReadingFormat
38 {
39 byte0,
40 byte3,
41 nineBit,
42 tenBit,
43 elevenBit,
44 elevenBitShift,
45 linearElevenBit,
46 fifteenBit
47 };
48
49 namespace ipmi
50 {
51 namespace sensor
52 {
53 constexpr uint8_t netFn = 0x04;
54 constexpr uint8_t getSensorReading = 0x2d;
55
isValid(const std::vector<uint8_t> & data)56 static inline bool isValid(const std::vector<uint8_t>& data)
57 {
58 constexpr auto readingUnavailableBit = 5;
59
60 // Proper 'Get Sensor Reading' response has at least 4 bytes, including
61 // Completion Code. Our IPMB stack strips Completion Code from payload so we
62 // compare here against the rest of payload
63 if (data.size() < 3)
64 {
65 return false;
66 }
67
68 // Per IPMI 'Get Sensor Reading' specification
69 if ((data[1] & (1 << readingUnavailableBit)) != 0)
70 {
71 return false;
72 }
73
74 return true;
75 }
76
77 } // namespace sensor
78 namespace me_bridge
79 {
80 constexpr uint8_t netFn = 0x2e;
81 constexpr uint8_t sendRawPmbus = 0xd9;
82 } // namespace me_bridge
83 } // namespace ipmi
84
85 using IpmbMethodType =
86 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
87
88 struct IpmbSensor :
89 public Sensor,
90 public std::enable_shared_from_this<IpmbSensor>
91 {
92 IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
93 boost::asio::io_context& io, const std::string& name,
94 const std::string& sensorConfiguration,
95 sdbusplus::asio::object_server& objectServer,
96 std::vector<thresholds::Threshold>&& thresholdData,
97 uint8_t deviceAddress, uint8_t hostSMbusIndex, float pollRate,
98 std::string& sensorTypeName);
99 ~IpmbSensor() override;
100
101 void checkThresholds() override;
102 void read();
103 void init();
104 std::string getSubTypeUnits() const;
105 void loadDefaults();
106 void runInitCmd();
107 static bool processReading(ReadingFormat readingFormat, uint8_t command,
108 const std::vector<uint8_t>& data, double& resp,
109 size_t errCount);
110 void parseConfigValues(const SensorBaseConfigMap& entry);
111 bool sensorClassType(const std::string& sensorClass);
112 void sensorSubType(const std::string& sensorTypeName);
113
114 IpmbType type = IpmbType::none;
115 IpmbSubType subType = IpmbSubType::none;
116 double scaleVal = 1.0;
117 double offsetVal = 0.0;
118 uint8_t commandAddress = 0;
119 uint8_t netfn = 0;
120 uint8_t command = 0;
121 uint8_t deviceAddress = 0;
122 uint8_t errorCount = 0;
123 uint8_t hostSMbusIndex = 0;
124 std::vector<uint8_t> commandData;
125 std::optional<uint8_t> initCommand;
126 std::vector<uint8_t> initData;
127 int sensorPollMs;
128
129 ReadingFormat readingFormat = ReadingFormat::byte0;
130
131 private:
132 void sendIpmbRequest();
133 sdbusplus::asio::object_server& objectServer;
134 boost::asio::steady_timer waitTimer;
135 void ipmbRequestCompletionCb(const boost::system::error_code& ec,
136 const IpmbMethodType& response);
137 };
138
139 void createSensors(
140 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
141 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
142 sensors,
143 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection);
144
145 void interfaceRemoved(
146 sdbusplus::message_t& message,
147 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
148 sensors);
149