blob: 30e9129a538e9f37bdf527cd298bb1735079227d [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
96 * @param[in] factor - the factor of the sensor target
97 * @param[in] offset - the offset of the sensor target
Jolie Ku69f2f482020-10-21 09:59:43 +080098 * @param[in] method - the method of out of range
99 * @param[in] threshold - the threshold of counter method
Matthew Barth8a8aa442021-11-19 14:13:13 -0600100 * @param[in] ignoreAboveMax - whether to ignore being above max or not
Matthew Barth177fe982020-05-26 11:05:19 -0500101 * @param[in] timeout - Normal timeout value to use
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500102 * @param[in] errorDelay - Delay in seconds before creating an error
103 * or std::nullopt if no errors.
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600104 * @param[in] countInterval - In count mode interval
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500105 *
Matthew Barth177fe982020-05-26 11:05:19 -0500106 * @param[in] event - Event loop reference
107 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500108 TachSensor(Mode mode, sdbusplus::bus_t& bus, Fan& fan,
Matthew Barth177fe982020-05-26 11:05:19 -0500109 const std::string& id, bool hasTarget, size_t funcDelay,
110 const std::string& interface, double factor, int64_t offset,
Matthew Barth8a8aa442021-11-19 14:13:13 -0600111 size_t method, size_t threshold, bool ignoreAboveMax,
112 size_t timeout, const std::optional<size_t>& errorDelay,
113 size_t countInterval, const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500114
Matthew Barth177fe982020-05-26 11:05:19 -0500115 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600116 * @brief Reads a property from the input message and stores it in value.
117 * T is the value type.
118 *
119 * Note: This can only be called once per message.
120 *
121 * @param[in] msg - the dbus message that contains the data
122 * @param[in] interface - the interface the property is on
123 * @param[in] propertName - the name of the property
124 * @param[out] value - the value to store the property value in
125 */
126 template <typename T>
Patrick Williamscb356d42022-07-22 19:26:53 -0500127 static void readPropertyFromMessage(sdbusplus::message_t& msg,
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600128 const std::string& interface,
129 const std::string& propertyName,
130 T& value)
131 {
132 std::string sensor;
133 std::map<std::string, std::variant<T>> data;
134 msg.read(sensor, data);
135
136 if (sensor.compare(interface) == 0)
137 {
138 auto propertyMap = data.find(propertyName);
139 if (propertyMap != data.end())
140 {
141 value = std::get<T>(propertyMap->second);
142 }
143 }
144 }
145
146 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500147 * @brief Returns the target speed value
148 */
149 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500150
Matthew Barth177fe982020-05-26 11:05:19 -0500151 /**
152 * @brief Returns the input speed value
153 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500154 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500155 {
156 return _tachInput;
157 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500158
Matthew Barth177fe982020-05-26 11:05:19 -0500159 /**
160 * @brief Returns true if sensor has a target
161 */
162 inline bool hasTarget() const
163 {
164 return _hasTarget;
165 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500166
Matthew Barth177fe982020-05-26 11:05:19 -0500167 /**
168 * @brief Returns the interface of the sensor target
169 */
170 inline std::string getInterface() const
171 {
172 return _interface;
173 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500174
Matthew Barth177fe982020-05-26 11:05:19 -0500175 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400176 * @brief Returns true if sensor has a D-Bus owner
177 */
178 inline bool hasOwner() const
179 {
180 return _hasOwner;
181 }
182
183 /**
184 * @brief sets D-Bus owner status
185 *
186 * @param[in] val - new owner status
187 */
188 inline void setOwner(bool val)
189 {
190 _hasOwner = val;
191 }
192
193 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500194 * @brief Returns the factor of the sensor target
195 */
196 inline double getFactor() const
197 {
198 return _factor;
199 }
Lei YU80f271b2018-01-31 15:24:46 +0800200
Matthew Barth177fe982020-05-26 11:05:19 -0500201 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400202 * @brief Returns a reference to the sensor's Fan object
203 */
204 inline Fan& getFan() const
205 {
206 return _fan;
207 }
208
209 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500210 * @brief Returns the offset of the sensor target
211 */
212 inline int64_t getOffset() const
213 {
214 return _offset;
215 }
Lei YU8e5d1972018-01-26 17:14:00 +0800216
Matthew Barth177fe982020-05-26 11:05:19 -0500217 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800218 * @brief Returns the method of out of range
219 */
220 inline size_t getMethod() const
221 {
222 return _method;
223 }
224
225 /**
226 * @brief Returns the threshold of count method
227 */
228 inline size_t getThreshold() const
229 {
230 return _threshold;
231 }
232
233 /**
234 * Set the sensor faulted counter
235 */
236 void setCounter(bool count);
237
238 /**
239 * @brief Returns the sensor faulted count
240 */
241 inline size_t getCounter() const
242 {
243 return _counter;
244 }
245
246 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500247 * Returns true if the hardware behind this
248 * sensor is considered working OK/functional.
249 */
250 inline bool functional() const
251 {
252 return _functional;
253 }
Lei YU8e5d1972018-01-26 17:14:00 +0800254
Matthew Barth177fe982020-05-26 11:05:19 -0500255 /**
256 * Set the functional status and update inventory to match
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500257 *
258 * @param[in] functional - The new state
259 * @param[in] skipErrorTimer - If setting the sensor to
260 * nonfunctional, don't start the error timer.
Matthew Barth177fe982020-05-26 11:05:19 -0500261 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500262 void setFunctional(bool functional, bool skipErrorTimer = false);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500263
Matthew Barth177fe982020-05-26 11:05:19 -0500264 /**
265 * @brief Says if the timer is running or not
266 *
267 * @return bool - if timer is currently running
268 */
269 inline bool timerRunning()
270 {
271 return _timer.isEnabled();
272 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500273
Matthew Barth177fe982020-05-26 11:05:19 -0500274 /**
275 * @brief Stops the timer when the given mode differs and starts
276 * the associated timer for the mode given if not already running
277 *
278 * @param[in] mode - mode of timer to start
279 */
280 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500281
Matthew Barth177fe982020-05-26 11:05:19 -0500282 /**
283 * @brief Stops the timer
284 */
285 inline void stopTimer()
286 {
Matt Spinler1d7379e2021-03-01 16:16:17 -0600287 phosphor::logging::log<phosphor::logging::level::DEBUG>(
Matthew Barth0d0e3552021-01-27 12:31:28 -0600288 fmt::format("Stop running timer on tach sensor {}.", _name)
289 .c_str());
Matthew Barth177fe982020-05-26 11:05:19 -0500290 _timer.setEnabled(false);
291 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500292
Matthew Barth177fe982020-05-26 11:05:19 -0500293 /**
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600294 * @brief Says if the count timer is running
295 *
296 * @return bool - If count timer running
297 */
298 inline bool countTimerRunning() const
299 {
300 return _countTimer && _countTimer->isEnabled();
301 }
302
303 /**
304 * @brief Stops the count timer
305 */
306 void stopCountTimer();
307
308 /**
309 * @brief Starts the count timer
310 */
311 void startCountTimer();
312
313 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500314 * @brief Return the given timer mode's delay time
315 *
316 * @param[in] mode - mode of timer to get delay time for
317 */
318 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500319
Matthew Barth177fe982020-05-26 11:05:19 -0500320 /**
321 * Returns the sensor name
322 */
323 inline const std::string& name() const
324 {
325 return _name;
326 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500327
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500328 /**
329 * @brief Says if the error timer is running
330 *
331 * @return bool - If the timer is running
332 */
333 bool errorTimerRunning() const
334 {
335 if (_errorTimer && _errorTimer->isEnabled())
336 {
337 return true;
338 }
339 return false;
340 }
341
Matthew Barth7c23a042021-01-26 16:21:45 -0600342 /**
343 * @brief Get the current allowed range of speeds
344 *
345 * @param[in] deviation - The configured deviation(in percent) allowed
346 *
Matthew Barth8a8aa442021-11-19 14:13:13 -0600347 * @return pair - Min/Max(optional) range of speeds allowed
Matthew Barth7c23a042021-01-26 16:21:45 -0600348 */
Matthew Barth8a8aa442021-11-19 14:13:13 -0600349 std::pair<uint64_t, std::optional<uint64_t>>
350 getRange(const size_t deviation) const;
Matthew Barth7c23a042021-01-26 16:21:45 -0600351
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600352 /**
353 * @brief Processes the current state of the sensor
354 */
355 void processState();
356
357 /**
358 * @brief Resets the monitoring method of the sensor
359 */
360 void resetMethod();
361
Matt Spinler4283c5d2021-03-01 15:56:00 -0600362 /**
363 * @brief Refreshes the tach input and target values by
364 * reading them from D-Bus.
365 */
366 void updateTachAndTarget();
367
Mike Capps7b34ee02022-05-04 14:16:12 -0400368 /**
369 * @brief return the previous tach values
370 */
371 const std::deque<uint64_t>& getPrevTach() const
372 {
373 return _prevTachs;
374 }
375
376 /**
377 * @brief return the previous target values
378 */
379 const std::deque<uint64_t>& getPrevTarget() const
380 {
381 return _prevTargets;
382 }
383
Matthew Barth177fe982020-05-26 11:05:19 -0500384 private:
385 /**
386 * @brief Returns the match string to use for matching
387 * on a properties changed signal.
388 */
389 std::string getMatchString(const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500390
Matthew Barth177fe982020-05-26 11:05:19 -0500391 /**
392 * @brief Reads the Target property and stores in _tachTarget.
393 * Also calls Fan::tachChanged().
394 *
395 * @param[in] msg - the dbus message
396 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500397 void handleTargetChange(sdbusplus::message_t& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500398
Matthew Barth177fe982020-05-26 11:05:19 -0500399 /**
400 * @brief Reads the Value property and stores in _tachInput.
401 * Also calls Fan::tachChanged().
402 *
403 * @param[in] msg - the dbus message
404 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500405 void handleTachChange(sdbusplus::message_t& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500406
Matthew Barth177fe982020-05-26 11:05:19 -0500407 /**
408 * @brief Updates the Functional property in the inventory
409 * for this tach sensor based on the value passed in.
410 *
411 * @param[in] functional - If the Functional property should
412 * be set to true or false.
413 */
414 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500415
Matthew Barth177fe982020-05-26 11:05:19 -0500416 /**
417 * @brief the dbus object
418 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500419 sdbusplus::bus_t& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500420
Matthew Barth177fe982020-05-26 11:05:19 -0500421 /**
422 * @brief Reference to the parent Fan object
423 */
424 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500425
Matthew Barth177fe982020-05-26 11:05:19 -0500426 /**
427 * @brief The name of the sensor, including the full path
428 *
429 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
430 */
431 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500432
Matthew Barth177fe982020-05-26 11:05:19 -0500433 /**
434 * @brief The inventory name of the sensor, including the full path
435 */
436 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500437
Matthew Barth177fe982020-05-26 11:05:19 -0500438 /**
439 * @brief If functional (not too slow). The parent
440 * fan object sets this.
441 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500442 bool _functional = true;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500443
Matthew Barth177fe982020-05-26 11:05:19 -0500444 /**
445 * @brief If the sensor has a Target property (can set speed)
446 */
447 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600448
Matthew Barth177fe982020-05-26 11:05:19 -0500449 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400450 * @brief If the sensor has a D-Bus owner
451 */
452 bool _hasOwner = true;
453
454 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500455 * @brief Amount of time to delay updating to functional
456 */
457 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500458
Matthew Barth177fe982020-05-26 11:05:19 -0500459 /**
460 * @brief The interface that the target implements
461 */
462 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500463
Matthew Barth177fe982020-05-26 11:05:19 -0500464 /**
465 * @brief The factor of target to get fan rpm
466 */
467 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600468
Matthew Barth177fe982020-05-26 11:05:19 -0500469 /**
470 * @brief The offset of target to get fan rpm
471 */
472 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800473
Matthew Barth177fe982020-05-26 11:05:19 -0500474 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800475 * @brief The method of out of range
476 */
477 const size_t _method;
478
479 /**
480 * @brief The threshold for count method
481 */
482 const size_t _threshold;
483
484 /**
Matthew Barth8a8aa442021-11-19 14:13:13 -0600485 * @brief Whether to ignore being above the max or not
486 */
487 const bool _ignoreAboveMax;
488
489 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800490 * @brief The counter for count method
491 */
492 size_t _counter = 0;
493
494 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500495 * @brief The input speed, from the Value dbus property
496 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500497 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800498
Matthew Barth177fe982020-05-26 11:05:19 -0500499 /**
500 * @brief The current target speed, from the Target dbus property
501 * (if applicable)
502 */
503 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800504
Matthew Barth177fe982020-05-26 11:05:19 -0500505 /**
506 * @brief The timeout value to use
507 */
508 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500509
Matthew Barth177fe982020-05-26 11:05:19 -0500510 /**
511 * @brief Mode that current timer is in
512 */
513 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500514
Matthew Barth177fe982020-05-26 11:05:19 -0500515 /**
516 * The timer object
517 */
518 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500519
Matthew Barth177fe982020-05-26 11:05:19 -0500520 /**
521 * @brief The match object for the Value properties changed signal
522 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600523 std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600524
Matthew Barth177fe982020-05-26 11:05:19 -0500525 /**
526 * @brief The match object for the Target properties changed signal
527 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600528 std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500529
530 /**
531 * @brief The number of seconds to wait between a sensor being set
532 * to nonfunctional and creating an error for it.
533 *
534 * If std::nullopt, no errors will be created.
535 */
536 const std::optional<size_t> _errorDelay;
537
538 /**
539 * @brief The timer that uses _errorDelay. When it expires an error
540 * will be created for a faulted fan sensor (rotor).
541 *
542 * If _errorDelay is std::nullopt, then this won't be created.
543 */
544 std::unique_ptr<
545 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
546 _errorTimer;
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600547
548 /**
549 * @brief The interval, in seconds, to use for the timer that runs
550 * the checks when using the 'count' method.
551 */
552 size_t _countInterval;
553
554 /**
555 * @brief The timer used by the 'count' method for determining
556 * functional status.
557 */
558 std::unique_ptr<
559 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
560 _countTimer;
Mike Capps7b34ee02022-05-04 14:16:12 -0400561
562 /**
563 * @brief record of previous targets
564 */
565 std::deque<uint64_t> _prevTargets;
566
567 /**
568 * @brief record of previous tach readings
569 */
570 std::deque<uint64_t> _prevTachs;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500571};
572
Matthew Barth177fe982020-05-26 11:05:19 -0500573} // namespace monitor
574} // namespace fan
575} // namespace phosphor