blob: 88c8547bc57d3727eabab0c37bcc14eaad9b22b5 [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001#pragma once
2
Matt Spinlerabf8da32017-04-27 14:08:45 -05003#include <sdbusplus/bus.hpp>
4#include <sdbusplus/server.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07005#include <sdeventplus/clock.hpp>
William A. Kennington III1cfc2f12018-10-19 17:29:46 -07006#include <sdeventplus/event.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07007#include <sdeventplus/utility/timer.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -05008
Matthew Barth177fe982020-05-26 11:05:19 -05009#include <chrono>
10
Matt Spinlerabf8da32017-04-27 14:08:45 -050011namespace phosphor
12{
13namespace fan
14{
15namespace monitor
16{
17
18class Fan;
19
Matt Spinler78689dd2017-09-28 10:12:07 -050020constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
Matt Spinlerabf8da32017-04-27 14:08:45 -050021
22/**
Matthew Barth0a9fe162018-01-26 12:53:15 -060023 * The mode fan monitor will run in:
24 * - init - only do the initialization steps
25 * - monitor - run normal monitoring algorithm
26 */
27enum class Mode
28{
29 init,
30 monitor
31};
32
33/**
Matthew Barth3800ae72018-02-19 16:08:04 -060034 * The mode that the timer is running in:
35 * - func - Transition to functional state timer
36 * - nonfunc - Transition to nonfunctional state timer
37 */
38enum class TimerMode
39{
40 func,
41 nonfunc
42};
43
44/**
Jolie Ku69f2f482020-10-21 09:59:43 +080045 * The mode that the method is running in:
46 * - time - Use a percentage based deviation
47 * - count - Run up/down count fault detection
48 */
49enum MethodMode
50{
51 timebased = 0,
52 count
53};
54
55/**
Matt Spinlerabf8da32017-04-27 14:08:45 -050056 * @class TachSensor
57 *
58 * This class represents the sensor that reads a tach value.
59 * It may also support a Target, which is the property used to
60 * set a speed. Since it doesn't necessarily have a Target, it
61 * won't for sure know if it is running too slow, so it leaves
62 * that determination to other code.
63 *
64 * This class has a parent Fan object that knows about all
65 * sensors for that fan.
66 */
67class TachSensor
68{
Matthew Barth177fe982020-05-26 11:05:19 -050069 public:
70 TachSensor() = delete;
71 TachSensor(const TachSensor&) = delete;
72 // TachSensor is not moveable since the this pointer is used as systemd
73 // callback context.
74 TachSensor(TachSensor&&) = delete;
75 TachSensor& operator=(const TachSensor&) = delete;
76 TachSensor& operator=(TachSensor&&) = delete;
77 ~TachSensor() = default;
Matt Spinlerabf8da32017-04-27 14:08:45 -050078
Matthew Barth177fe982020-05-26 11:05:19 -050079 /**
80 * @brief Constructor
81 *
82 * @param[in] mode - mode of fan monitor
83 * @param[in] bus - the dbus object
84 * @param[in] fan - the parent fan object
85 * @param[in] id - the id of the sensor
86 * @param[in] hasTarget - if the sensor supports
87 * setting the speed
88 * @param[in] funcDelay - Delay to mark functional
89 * @param[in] interface - the interface of the target
90 * @param[in] factor - the factor of the sensor target
91 * @param[in] offset - the offset of the sensor target
Jolie Ku69f2f482020-10-21 09:59:43 +080092 * @param[in] method - the method of out of range
93 * @param[in] threshold - the threshold of counter method
Matthew Barth177fe982020-05-26 11:05:19 -050094 * @param[in] timeout - Normal timeout value to use
Matt Spinlerf13b42e2020-10-26 15:29:49 -050095 * @param[in] errorDelay - Delay in seconds before creating an error
96 * or std::nullopt if no errors.
97 *
Matthew Barth177fe982020-05-26 11:05:19 -050098 * @param[in] event - Event loop reference
99 */
100 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan,
101 const std::string& id, bool hasTarget, size_t funcDelay,
102 const std::string& interface, double factor, int64_t offset,
Jolie Ku69f2f482020-10-21 09:59:43 +0800103 size_t method, size_t threshold, size_t timeout,
104 const std::optional<size_t>& errorDelay,
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500105 const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500106
Matthew Barth177fe982020-05-26 11:05:19 -0500107 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600108 * @brief Reads a property from the input message and stores it in value.
109 * T is the value type.
110 *
111 * Note: This can only be called once per message.
112 *
113 * @param[in] msg - the dbus message that contains the data
114 * @param[in] interface - the interface the property is on
115 * @param[in] propertName - the name of the property
116 * @param[out] value - the value to store the property value in
117 */
118 template <typename T>
119 static void readPropertyFromMessage(sdbusplus::message::message& msg,
120 const std::string& interface,
121 const std::string& propertyName,
122 T& value)
123 {
124 std::string sensor;
125 std::map<std::string, std::variant<T>> data;
126 msg.read(sensor, data);
127
128 if (sensor.compare(interface) == 0)
129 {
130 auto propertyMap = data.find(propertyName);
131 if (propertyMap != data.end())
132 {
133 value = std::get<T>(propertyMap->second);
134 }
135 }
136 }
137
138 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500139 * @brief Returns the target speed value
140 */
141 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500142
Matthew Barth177fe982020-05-26 11:05:19 -0500143 /**
144 * @brief Returns the input speed value
145 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500146 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500147 {
148 return _tachInput;
149 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500150
Matthew Barth177fe982020-05-26 11:05:19 -0500151 /**
152 * @brief Returns true if sensor has a target
153 */
154 inline bool hasTarget() const
155 {
156 return _hasTarget;
157 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500158
Matthew Barth177fe982020-05-26 11:05:19 -0500159 /**
160 * @brief Returns the interface of the sensor target
161 */
162 inline std::string getInterface() const
163 {
164 return _interface;
165 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500166
Matthew Barth177fe982020-05-26 11:05:19 -0500167 /**
168 * @brief Returns the factor of the sensor target
169 */
170 inline double getFactor() const
171 {
172 return _factor;
173 }
Lei YU80f271b2018-01-31 15:24:46 +0800174
Matthew Barth177fe982020-05-26 11:05:19 -0500175 /**
176 * @brief Returns the offset of the sensor target
177 */
178 inline int64_t getOffset() const
179 {
180 return _offset;
181 }
Lei YU8e5d1972018-01-26 17:14:00 +0800182
Matthew Barth177fe982020-05-26 11:05:19 -0500183 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800184 * @brief Returns the method of out of range
185 */
186 inline size_t getMethod() const
187 {
188 return _method;
189 }
190
191 /**
192 * @brief Returns the threshold of count method
193 */
194 inline size_t getThreshold() const
195 {
196 return _threshold;
197 }
198
199 /**
200 * Set the sensor faulted counter
201 */
202 void setCounter(bool count);
203
204 /**
205 * @brief Returns the sensor faulted count
206 */
207 inline size_t getCounter() const
208 {
209 return _counter;
210 }
211
212 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500213 * Returns true if the hardware behind this
214 * sensor is considered working OK/functional.
215 */
216 inline bool functional() const
217 {
218 return _functional;
219 }
Lei YU8e5d1972018-01-26 17:14:00 +0800220
Matthew Barth177fe982020-05-26 11:05:19 -0500221 /**
222 * Set the functional status and update inventory to match
223 */
224 void setFunctional(bool functional);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500225
Matthew Barth177fe982020-05-26 11:05:19 -0500226 /**
227 * @brief Says if the timer is running or not
228 *
229 * @return bool - if timer is currently running
230 */
231 inline bool timerRunning()
232 {
233 return _timer.isEnabled();
234 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500235
Matthew Barth177fe982020-05-26 11:05:19 -0500236 /**
237 * @brief Stops the timer when the given mode differs and starts
238 * the associated timer for the mode given if not already running
239 *
240 * @param[in] mode - mode of timer to start
241 */
242 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500243
Matthew Barth177fe982020-05-26 11:05:19 -0500244 /**
245 * @brief Stops the timer
246 */
247 inline void stopTimer()
248 {
249 _timer.setEnabled(false);
250 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500251
Matthew Barth177fe982020-05-26 11:05:19 -0500252 /**
253 * @brief Return the given timer mode's delay time
254 *
255 * @param[in] mode - mode of timer to get delay time for
256 */
257 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500258
Matthew Barth177fe982020-05-26 11:05:19 -0500259 /**
260 * Returns the sensor name
261 */
262 inline const std::string& name() const
263 {
264 return _name;
265 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500266
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500267 /**
268 * @brief Says if the error timer is running
269 *
270 * @return bool - If the timer is running
271 */
272 bool errorTimerRunning() const
273 {
274 if (_errorTimer && _errorTimer->isEnabled())
275 {
276 return true;
277 }
278 return false;
279 }
280
Matthew Barth177fe982020-05-26 11:05:19 -0500281 private:
282 /**
283 * @brief Returns the match string to use for matching
284 * on a properties changed signal.
285 */
286 std::string getMatchString(const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500287
Matthew Barth177fe982020-05-26 11:05:19 -0500288 /**
289 * @brief Reads the Target property and stores in _tachTarget.
290 * Also calls Fan::tachChanged().
291 *
292 * @param[in] msg - the dbus message
293 */
294 void handleTargetChange(sdbusplus::message::message& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500295
Matthew Barth177fe982020-05-26 11:05:19 -0500296 /**
297 * @brief Reads the Value property and stores in _tachInput.
298 * Also calls Fan::tachChanged().
299 *
300 * @param[in] msg - the dbus message
301 */
302 void handleTachChange(sdbusplus::message::message& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500303
Matthew Barth177fe982020-05-26 11:05:19 -0500304 /**
305 * @brief Updates the Functional property in the inventory
306 * for this tach sensor based on the value passed in.
307 *
308 * @param[in] functional - If the Functional property should
309 * be set to true or false.
310 */
311 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500312
Matthew Barth177fe982020-05-26 11:05:19 -0500313 /**
314 * @brief the dbus object
315 */
316 sdbusplus::bus::bus& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500317
Matthew Barth177fe982020-05-26 11:05:19 -0500318 /**
319 * @brief Reference to the parent Fan object
320 */
321 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500322
Matthew Barth177fe982020-05-26 11:05:19 -0500323 /**
324 * @brief The name of the sensor, including the full path
325 *
326 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
327 */
328 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500329
Matthew Barth177fe982020-05-26 11:05:19 -0500330 /**
331 * @brief The inventory name of the sensor, including the full path
332 */
333 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500334
Matthew Barth177fe982020-05-26 11:05:19 -0500335 /**
336 * @brief If functional (not too slow). The parent
337 * fan object sets this.
338 */
339 bool _functional;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500340
Matthew Barth177fe982020-05-26 11:05:19 -0500341 /**
342 * @brief If the sensor has a Target property (can set speed)
343 */
344 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600345
Matthew Barth177fe982020-05-26 11:05:19 -0500346 /**
347 * @brief Amount of time to delay updating to functional
348 */
349 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500350
Matthew Barth177fe982020-05-26 11:05:19 -0500351 /**
352 * @brief The interface that the target implements
353 */
354 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500355
Matthew Barth177fe982020-05-26 11:05:19 -0500356 /**
357 * @brief The factor of target to get fan rpm
358 */
359 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600360
Matthew Barth177fe982020-05-26 11:05:19 -0500361 /**
362 * @brief The offset of target to get fan rpm
363 */
364 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800365
Matthew Barth177fe982020-05-26 11:05:19 -0500366 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800367 * @brief The method of out of range
368 */
369 const size_t _method;
370
371 /**
372 * @brief The threshold for count method
373 */
374 const size_t _threshold;
375
376 /**
377 * @brief The counter for count method
378 */
379 size_t _counter = 0;
380
381 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500382 * @brief The input speed, from the Value dbus property
383 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500384 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800385
Matthew Barth177fe982020-05-26 11:05:19 -0500386 /**
387 * @brief The current target speed, from the Target dbus property
388 * (if applicable)
389 */
390 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800391
Matthew Barth177fe982020-05-26 11:05:19 -0500392 /**
393 * @brief The timeout value to use
394 */
395 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500396
Matthew Barth177fe982020-05-26 11:05:19 -0500397 /**
398 * @brief Mode that current timer is in
399 */
400 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500401
Matthew Barth177fe982020-05-26 11:05:19 -0500402 /**
403 * The timer object
404 */
405 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500406
Matthew Barth177fe982020-05-26 11:05:19 -0500407 /**
408 * @brief The match object for the Value properties changed signal
409 */
410 std::unique_ptr<sdbusplus::server::match::match> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600411
Matthew Barth177fe982020-05-26 11:05:19 -0500412 /**
413 * @brief The match object for the Target properties changed signal
414 */
415 std::unique_ptr<sdbusplus::server::match::match> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500416
417 /**
418 * @brief The number of seconds to wait between a sensor being set
419 * to nonfunctional and creating an error for it.
420 *
421 * If std::nullopt, no errors will be created.
422 */
423 const std::optional<size_t> _errorDelay;
424
425 /**
426 * @brief The timer that uses _errorDelay. When it expires an error
427 * will be created for a faulted fan sensor (rotor).
428 *
429 * If _errorDelay is std::nullopt, then this won't be created.
430 */
431 std::unique_ptr<
432 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
433 _errorTimer;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500434};
435
Matthew Barth177fe982020-05-26 11:05:19 -0500436} // namespace monitor
437} // namespace fan
438} // namespace phosphor