blob: 875c578ec8eea6c679098abc10db13fe5d2a5287 [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001#pragma once
2
Matthew Barth0d0e3552021-01-27 12:31:28 -06003#include <fmt/format.h>
4
5#include <phosphor-logging/log.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -05006#include <sdbusplus/bus.hpp>
Patrick Williams3ea9ec22021-11-19 12:21:08 -06007#include <sdbusplus/bus/match.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07008#include <sdeventplus/clock.hpp>
William A. Kennington III1cfc2f12018-10-19 17:29:46 -07009#include <sdeventplus/event.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -070010#include <sdeventplus/utility/timer.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -050011
Matthew Barth177fe982020-05-26 11:05:19 -050012#include <chrono>
Mike Capps7b34ee02022-05-04 14:16:12 -040013#include <deque>
Matthew Barth8a8aa442021-11-19 14:13:13 -060014#include <optional>
Matthew Barth7c23a042021-01-26 16:21:45 -060015#include <utility>
Matthew Barth177fe982020-05-26 11:05:19 -050016
Matt Spinlerabf8da32017-04-27 14:08:45 -050017namespace phosphor
18{
19namespace fan
20{
21namespace monitor
22{
23
24class Fan;
25
Matt Spinler78689dd2017-09-28 10:12:07 -050026constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
Matt Spinlerabf8da32017-04-27 14:08:45 -050027
28/**
Matthew Barth0a9fe162018-01-26 12:53:15 -060029 * The mode fan monitor will run in:
30 * - init - only do the initialization steps
31 * - monitor - run normal monitoring algorithm
32 */
33enum class Mode
34{
35 init,
36 monitor
37};
38
39/**
Matthew Barth3800ae72018-02-19 16:08:04 -060040 * The mode that the timer is running in:
41 * - func - Transition to functional state timer
42 * - nonfunc - Transition to nonfunctional state timer
43 */
44enum class TimerMode
45{
46 func,
47 nonfunc
48};
49
50/**
Jolie Ku69f2f482020-10-21 09:59:43 +080051 * The mode that the method is running in:
52 * - time - Use a percentage based deviation
53 * - count - Run up/down count fault detection
54 */
55enum MethodMode
56{
57 timebased = 0,
58 count
59};
60
61/**
Matt Spinlerabf8da32017-04-27 14:08:45 -050062 * @class TachSensor
63 *
64 * This class represents the sensor that reads a tach value.
65 * It may also support a Target, which is the property used to
66 * set a speed. Since it doesn't necessarily have a Target, it
67 * won't for sure know if it is running too slow, so it leaves
68 * that determination to other code.
69 *
70 * This class has a parent Fan object that knows about all
71 * sensors for that fan.
72 */
73class TachSensor
74{
Matthew Barth177fe982020-05-26 11:05:19 -050075 public:
76 TachSensor() = delete;
77 TachSensor(const TachSensor&) = delete;
78 // TachSensor is not moveable since the this pointer is used as systemd
79 // callback context.
80 TachSensor(TachSensor&&) = delete;
81 TachSensor& operator=(const TachSensor&) = delete;
82 TachSensor& operator=(TachSensor&&) = delete;
83 ~TachSensor() = default;
Matt Spinlerabf8da32017-04-27 14:08:45 -050084
Matthew Barth177fe982020-05-26 11:05:19 -050085 /**
86 * @brief Constructor
87 *
88 * @param[in] mode - mode of fan monitor
89 * @param[in] bus - the dbus object
90 * @param[in] fan - the parent fan object
91 * @param[in] id - the id of the sensor
92 * @param[in] hasTarget - if the sensor supports
93 * setting the speed
94 * @param[in] funcDelay - Delay to mark functional
95 * @param[in] interface - the interface of the target
Chau Ly27cc39f2022-09-20 08:16:56 +000096 * @param[in] path - the object path of the sensor target
Matthew Barth177fe982020-05-26 11:05:19 -050097 * @param[in] factor - the factor of the sensor target
98 * @param[in] offset - the offset of the sensor target
Jolie Ku69f2f482020-10-21 09:59:43 +080099 * @param[in] method - the method of out of range
100 * @param[in] threshold - the threshold of counter method
Matthew Barth8a8aa442021-11-19 14:13:13 -0600101 * @param[in] ignoreAboveMax - whether to ignore being above max or not
Matthew Barth177fe982020-05-26 11:05:19 -0500102 * @param[in] timeout - Normal timeout value to use
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500103 * @param[in] errorDelay - Delay in seconds before creating an error
104 * or std::nullopt if no errors.
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600105 * @param[in] countInterval - In count mode interval
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500106 *
Matthew Barth177fe982020-05-26 11:05:19 -0500107 * @param[in] event - Event loop reference
108 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500109 TachSensor(Mode mode, sdbusplus::bus_t& bus, Fan& fan,
Matthew Barth177fe982020-05-26 11:05:19 -0500110 const std::string& id, bool hasTarget, size_t funcDelay,
Chau Ly27cc39f2022-09-20 08:16:56 +0000111 const std::string& interface, const std::string& path,
112 double factor, int64_t offset, size_t method, size_t threshold,
113 bool ignoreAboveMax, size_t timeout,
114 const std::optional<size_t>& errorDelay, size_t countInterval,
115 const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500116
Matthew Barth177fe982020-05-26 11:05:19 -0500117 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600118 * @brief Reads a property from the input message and stores it in value.
119 * T is the value type.
120 *
121 * Note: This can only be called once per message.
122 *
123 * @param[in] msg - the dbus message that contains the data
124 * @param[in] interface - the interface the property is on
125 * @param[in] propertName - the name of the property
126 * @param[out] value - the value to store the property value in
127 */
128 template <typename T>
Patrick Williamscb356d42022-07-22 19:26:53 -0500129 static void readPropertyFromMessage(sdbusplus::message_t& msg,
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600130 const std::string& interface,
131 const std::string& propertyName,
132 T& value)
133 {
134 std::string sensor;
135 std::map<std::string, std::variant<T>> data;
136 msg.read(sensor, data);
137
138 if (sensor.compare(interface) == 0)
139 {
140 auto propertyMap = data.find(propertyName);
141 if (propertyMap != data.end())
142 {
143 value = std::get<T>(propertyMap->second);
144 }
145 }
146 }
147
148 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500149 * @brief Returns the target speed value
150 */
151 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500152
Matthew Barth177fe982020-05-26 11:05:19 -0500153 /**
154 * @brief Returns the input speed value
155 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500156 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500157 {
158 return _tachInput;
159 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500160
Matthew Barth177fe982020-05-26 11:05:19 -0500161 /**
162 * @brief Returns true if sensor has a target
163 */
164 inline bool hasTarget() const
165 {
166 return _hasTarget;
167 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500168
Matthew Barth177fe982020-05-26 11:05:19 -0500169 /**
170 * @brief Returns the interface of the sensor target
171 */
172 inline std::string getInterface() const
173 {
174 return _interface;
175 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500176
Matthew Barth177fe982020-05-26 11:05:19 -0500177 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400178 * @brief Returns true if sensor has a D-Bus owner
179 */
180 inline bool hasOwner() const
181 {
182 return _hasOwner;
183 }
184
185 /**
186 * @brief sets D-Bus owner status
187 *
188 * @param[in] val - new owner status
189 */
190 inline void setOwner(bool val)
191 {
192 _hasOwner = val;
193 }
194
195 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500196 * @brief Returns the factor of the sensor target
197 */
198 inline double getFactor() const
199 {
200 return _factor;
201 }
Lei YU80f271b2018-01-31 15:24:46 +0800202
Matthew Barth177fe982020-05-26 11:05:19 -0500203 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400204 * @brief Returns a reference to the sensor's Fan object
205 */
206 inline Fan& getFan() const
207 {
208 return _fan;
209 }
210
211 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500212 * @brief Returns the offset of the sensor target
213 */
214 inline int64_t getOffset() const
215 {
216 return _offset;
217 }
Lei YU8e5d1972018-01-26 17:14:00 +0800218
Matthew Barth177fe982020-05-26 11:05:19 -0500219 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800220 * @brief Returns the method of out of range
221 */
222 inline size_t getMethod() const
223 {
224 return _method;
225 }
226
227 /**
228 * @brief Returns the threshold of count method
229 */
230 inline size_t getThreshold() const
231 {
232 return _threshold;
233 }
234
235 /**
236 * Set the sensor faulted counter
237 */
238 void setCounter(bool count);
239
240 /**
241 * @brief Returns the sensor faulted count
242 */
243 inline size_t getCounter() const
244 {
245 return _counter;
246 }
247
248 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500249 * Returns true if the hardware behind this
250 * sensor is considered working OK/functional.
251 */
252 inline bool functional() const
253 {
254 return _functional;
255 }
Lei YU8e5d1972018-01-26 17:14:00 +0800256
Matthew Barth177fe982020-05-26 11:05:19 -0500257 /**
258 * Set the functional status and update inventory to match
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500259 *
260 * @param[in] functional - The new state
261 * @param[in] skipErrorTimer - If setting the sensor to
262 * nonfunctional, don't start the error timer.
Matthew Barth177fe982020-05-26 11:05:19 -0500263 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500264 void setFunctional(bool functional, bool skipErrorTimer = false);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500265
Matthew Barth177fe982020-05-26 11:05:19 -0500266 /**
267 * @brief Says if the timer is running or not
268 *
269 * @return bool - if timer is currently running
270 */
271 inline bool timerRunning()
272 {
273 return _timer.isEnabled();
274 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500275
Matthew Barth177fe982020-05-26 11:05:19 -0500276 /**
277 * @brief Stops the timer when the given mode differs and starts
278 * the associated timer for the mode given if not already running
279 *
280 * @param[in] mode - mode of timer to start
281 */
282 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500283
Matthew Barth177fe982020-05-26 11:05:19 -0500284 /**
285 * @brief Stops the timer
286 */
287 inline void stopTimer()
288 {
Matt Spinler1d7379e2021-03-01 16:16:17 -0600289 phosphor::logging::log<phosphor::logging::level::DEBUG>(
Matthew Barth0d0e3552021-01-27 12:31:28 -0600290 fmt::format("Stop running timer on tach sensor {}.", _name)
291 .c_str());
Matthew Barth177fe982020-05-26 11:05:19 -0500292 _timer.setEnabled(false);
293 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500294
Matthew Barth177fe982020-05-26 11:05:19 -0500295 /**
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600296 * @brief Says if the count timer is running
297 *
298 * @return bool - If count timer running
299 */
300 inline bool countTimerRunning() const
301 {
302 return _countTimer && _countTimer->isEnabled();
303 }
304
305 /**
306 * @brief Stops the count timer
307 */
308 void stopCountTimer();
309
310 /**
311 * @brief Starts the count timer
312 */
313 void startCountTimer();
314
315 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500316 * @brief Return the given timer mode's delay time
317 *
318 * @param[in] mode - mode of timer to get delay time for
319 */
320 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500321
Matthew Barth177fe982020-05-26 11:05:19 -0500322 /**
323 * Returns the sensor name
324 */
325 inline const std::string& name() const
326 {
327 return _name;
328 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500329
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500330 /**
331 * @brief Says if the error timer is running
332 *
333 * @return bool - If the timer is running
334 */
335 bool errorTimerRunning() const
336 {
337 if (_errorTimer && _errorTimer->isEnabled())
338 {
339 return true;
340 }
341 return false;
342 }
343
Matthew Barth7c23a042021-01-26 16:21:45 -0600344 /**
345 * @brief Get the current allowed range of speeds
346 *
347 * @param[in] deviation - The configured deviation(in percent) allowed
348 *
Matthew Barth8a8aa442021-11-19 14:13:13 -0600349 * @return pair - Min/Max(optional) range of speeds allowed
Matthew Barth7c23a042021-01-26 16:21:45 -0600350 */
Matthew Barth8a8aa442021-11-19 14:13:13 -0600351 std::pair<uint64_t, std::optional<uint64_t>>
352 getRange(const size_t deviation) const;
Matthew Barth7c23a042021-01-26 16:21:45 -0600353
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600354 /**
355 * @brief Processes the current state of the sensor
356 */
357 void processState();
358
359 /**
360 * @brief Resets the monitoring method of the sensor
361 */
362 void resetMethod();
363
Matt Spinler4283c5d2021-03-01 15:56:00 -0600364 /**
365 * @brief Refreshes the tach input and target values by
366 * reading them from D-Bus.
367 */
368 void updateTachAndTarget();
369
Mike Capps7b34ee02022-05-04 14:16:12 -0400370 /**
371 * @brief return the previous tach values
372 */
373 const std::deque<uint64_t>& getPrevTach() const
374 {
375 return _prevTachs;
376 }
377
378 /**
379 * @brief return the previous target values
380 */
381 const std::deque<uint64_t>& getPrevTarget() const
382 {
383 return _prevTargets;
384 }
385
Matthew Barth177fe982020-05-26 11:05:19 -0500386 private:
387 /**
388 * @brief Returns the match string to use for matching
389 * on a properties changed signal.
390 */
Chau Ly27cc39f2022-09-20 08:16:56 +0000391 std::string getMatchString(const std::optional<std::string> path,
392 const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500393
Matthew Barth177fe982020-05-26 11:05:19 -0500394 /**
395 * @brief Reads the Target property and stores in _tachTarget.
396 * Also calls Fan::tachChanged().
397 *
398 * @param[in] msg - the dbus message
399 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500400 void handleTargetChange(sdbusplus::message_t& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500401
Matthew Barth177fe982020-05-26 11:05:19 -0500402 /**
403 * @brief Reads the Value property and stores in _tachInput.
404 * Also calls Fan::tachChanged().
405 *
406 * @param[in] msg - the dbus message
407 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500408 void handleTachChange(sdbusplus::message_t& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500409
Matthew Barth177fe982020-05-26 11:05:19 -0500410 /**
411 * @brief Updates the Functional property in the inventory
412 * for this tach sensor based on the value passed in.
413 *
414 * @param[in] functional - If the Functional property should
415 * be set to true or false.
416 */
417 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500418
Matthew Barth177fe982020-05-26 11:05:19 -0500419 /**
420 * @brief the dbus object
421 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500422 sdbusplus::bus_t& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500423
Matthew Barth177fe982020-05-26 11:05:19 -0500424 /**
425 * @brief Reference to the parent Fan object
426 */
427 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500428
Matthew Barth177fe982020-05-26 11:05:19 -0500429 /**
430 * @brief The name of the sensor, including the full path
431 *
432 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
433 */
434 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500435
Matthew Barth177fe982020-05-26 11:05:19 -0500436 /**
437 * @brief The inventory name of the sensor, including the full path
438 */
439 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500440
Matthew Barth177fe982020-05-26 11:05:19 -0500441 /**
442 * @brief If functional (not too slow). The parent
443 * fan object sets this.
444 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500445 bool _functional = true;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500446
Matthew Barth177fe982020-05-26 11:05:19 -0500447 /**
448 * @brief If the sensor has a Target property (can set speed)
449 */
450 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600451
Matthew Barth177fe982020-05-26 11:05:19 -0500452 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400453 * @brief If the sensor has a D-Bus owner
454 */
455 bool _hasOwner = true;
456
457 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500458 * @brief Amount of time to delay updating to functional
459 */
460 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500461
Matthew Barth177fe982020-05-26 11:05:19 -0500462 /**
463 * @brief The interface that the target implements
464 */
465 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500466
Matthew Barth177fe982020-05-26 11:05:19 -0500467 /**
Chau Ly27cc39f2022-09-20 08:16:56 +0000468 * @brief The object path to set sensor's target
469 */
470 const std::string _path;
471
472 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500473 * @brief The factor of target to get fan rpm
474 */
475 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600476
Matthew Barth177fe982020-05-26 11:05:19 -0500477 /**
478 * @brief The offset of target to get fan rpm
479 */
480 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800481
Matthew Barth177fe982020-05-26 11:05:19 -0500482 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800483 * @brief The method of out of range
484 */
485 const size_t _method;
486
487 /**
488 * @brief The threshold for count method
489 */
490 const size_t _threshold;
491
492 /**
Matthew Barth8a8aa442021-11-19 14:13:13 -0600493 * @brief Whether to ignore being above the max or not
494 */
495 const bool _ignoreAboveMax;
496
497 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800498 * @brief The counter for count method
499 */
500 size_t _counter = 0;
501
502 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500503 * @brief The input speed, from the Value dbus property
504 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500505 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800506
Matthew Barth177fe982020-05-26 11:05:19 -0500507 /**
508 * @brief The current target speed, from the Target dbus property
509 * (if applicable)
510 */
511 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800512
Matthew Barth177fe982020-05-26 11:05:19 -0500513 /**
514 * @brief The timeout value to use
515 */
516 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500517
Matthew Barth177fe982020-05-26 11:05:19 -0500518 /**
519 * @brief Mode that current timer is in
520 */
521 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500522
Matthew Barth177fe982020-05-26 11:05:19 -0500523 /**
524 * The timer object
525 */
526 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500527
Matthew Barth177fe982020-05-26 11:05:19 -0500528 /**
529 * @brief The match object for the Value properties changed signal
530 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600531 std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600532
Matthew Barth177fe982020-05-26 11:05:19 -0500533 /**
534 * @brief The match object for the Target properties changed signal
535 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600536 std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500537
538 /**
539 * @brief The number of seconds to wait between a sensor being set
540 * to nonfunctional and creating an error for it.
541 *
542 * If std::nullopt, no errors will be created.
543 */
544 const std::optional<size_t> _errorDelay;
545
546 /**
547 * @brief The timer that uses _errorDelay. When it expires an error
548 * will be created for a faulted fan sensor (rotor).
549 *
550 * If _errorDelay is std::nullopt, then this won't be created.
551 */
552 std::unique_ptr<
553 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
554 _errorTimer;
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600555
556 /**
557 * @brief The interval, in seconds, to use for the timer that runs
558 * the checks when using the 'count' method.
559 */
560 size_t _countInterval;
561
562 /**
563 * @brief The timer used by the 'count' method for determining
564 * functional status.
565 */
566 std::unique_ptr<
567 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
568 _countTimer;
Mike Capps7b34ee02022-05-04 14:16:12 -0400569
570 /**
571 * @brief record of previous targets
572 */
573 std::deque<uint64_t> _prevTargets;
574
575 /**
576 * @brief record of previous tach readings
577 */
578 std::deque<uint64_t> _prevTachs;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500579};
580
Matthew Barth177fe982020-05-26 11:05:19 -0500581} // namespace monitor
582} // namespace fan
583} // namespace phosphor