blob: 1dea170d1836f150e4cdc582d89f5cb610c33069 [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001#pragma once
2
Anwaar Hadia00f6832025-03-27 15:03:11 +00003#include <phosphor-logging/lg2.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -05004#include <sdbusplus/bus.hpp>
Patrick Williams3ea9ec22021-11-19 12:21:08 -06005#include <sdbusplus/bus/match.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07006#include <sdeventplus/clock.hpp>
William A. Kennington III1cfc2f12018-10-19 17:29:46 -07007#include <sdeventplus/event.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07008#include <sdeventplus/utility/timer.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -05009
Matthew Barth177fe982020-05-26 11:05:19 -050010#include <chrono>
Mike Capps7b34ee02022-05-04 14:16:12 -040011#include <deque>
Matthew Barth8a8aa442021-11-19 14:13:13 -060012#include <optional>
Matthew Barth7c23a042021-01-26 16:21:45 -060013#include <utility>
Matthew Barth177fe982020-05-26 11:05:19 -050014
Matt Spinlerabf8da32017-04-27 14:08:45 -050015namespace phosphor
16{
17namespace fan
18{
19namespace monitor
20{
21
22class Fan;
23
Matt Spinler78689dd2017-09-28 10:12:07 -050024constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
Matt Spinlerabf8da32017-04-27 14:08:45 -050025
26/**
Matthew Barth0a9fe162018-01-26 12:53:15 -060027 * The mode fan monitor will run in:
28 * - init - only do the initialization steps
29 * - monitor - run normal monitoring algorithm
30 */
31enum class Mode
32{
33 init,
34 monitor
35};
36
37/**
Matthew Barth3800ae72018-02-19 16:08:04 -060038 * The mode that the timer is running in:
39 * - func - Transition to functional state timer
40 * - nonfunc - Transition to nonfunctional state timer
41 */
42enum class TimerMode
43{
44 func,
45 nonfunc
46};
47
48/**
Jolie Ku69f2f482020-10-21 09:59:43 +080049 * The mode that the method is running in:
50 * - time - Use a percentage based deviation
51 * - count - Run up/down count fault detection
52 */
53enum MethodMode
54{
55 timebased = 0,
56 count
57};
58
59/**
Matt Spinlerabf8da32017-04-27 14:08:45 -050060 * @class TachSensor
61 *
62 * This class represents the sensor that reads a tach value.
63 * It may also support a Target, which is the property used to
64 * set a speed. Since it doesn't necessarily have a Target, it
65 * won't for sure know if it is running too slow, so it leaves
66 * that determination to other code.
67 *
68 * This class has a parent Fan object that knows about all
69 * sensors for that fan.
70 */
71class TachSensor
72{
Matthew Barth177fe982020-05-26 11:05:19 -050073 public:
74 TachSensor() = delete;
75 TachSensor(const TachSensor&) = delete;
76 // TachSensor is not moveable since the this pointer is used as systemd
77 // callback context.
78 TachSensor(TachSensor&&) = delete;
79 TachSensor& operator=(const TachSensor&) = delete;
80 TachSensor& operator=(TachSensor&&) = delete;
81 ~TachSensor() = default;
Matt Spinlerabf8da32017-04-27 14:08:45 -050082
Matthew Barth177fe982020-05-26 11:05:19 -050083 /**
84 * @brief Constructor
85 *
86 * @param[in] mode - mode of fan monitor
87 * @param[in] bus - the dbus object
88 * @param[in] fan - the parent fan object
89 * @param[in] id - the id of the sensor
90 * @param[in] hasTarget - if the sensor supports
91 * setting the speed
92 * @param[in] funcDelay - Delay to mark functional
93 * @param[in] interface - the interface of the target
Chau Ly27cc39f2022-09-20 08:16:56 +000094 * @param[in] path - the object path of the sensor target
Matthew Barth177fe982020-05-26 11:05:19 -050095 * @param[in] factor - the factor of the sensor target
96 * @param[in] offset - the offset of the sensor target
Jolie Ku69f2f482020-10-21 09:59:43 +080097 * @param[in] method - the method of out of range
98 * @param[in] threshold - the threshold of counter method
Matthew Barth8a8aa442021-11-19 14:13:13 -060099 * @param[in] ignoreAboveMax - whether to ignore being above max or not
Matthew Barth177fe982020-05-26 11:05:19 -0500100 * @param[in] timeout - Normal timeout value to use
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500101 * @param[in] errorDelay - Delay in seconds before creating an error
102 * or std::nullopt if no errors.
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600103 * @param[in] countInterval - In count mode interval
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500104 *
Matthew Barth177fe982020-05-26 11:05:19 -0500105 * @param[in] event - Event loop reference
106 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500107 TachSensor(Mode mode, sdbusplus::bus_t& bus, Fan& fan,
Matthew Barth177fe982020-05-26 11:05:19 -0500108 const std::string& id, bool hasTarget, size_t funcDelay,
Chau Ly27cc39f2022-09-20 08:16:56 +0000109 const std::string& interface, const std::string& path,
110 double factor, int64_t offset, size_t method, size_t threshold,
111 bool ignoreAboveMax, size_t timeout,
112 const std::optional<size_t>& errorDelay, size_t countInterval,
113 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 Williamsdfddd642024-08-16 15:21:51 -0400127 static void readPropertyFromMessage(
128 sdbusplus::message_t& msg, const std::string& interface,
129 const std::string& propertyName, T& value)
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600130 {
131 std::string sensor;
132 std::map<std::string, std::variant<T>> data;
133 msg.read(sensor, data);
134
135 if (sensor.compare(interface) == 0)
136 {
137 auto propertyMap = data.find(propertyName);
138 if (propertyMap != data.end())
139 {
140 value = std::get<T>(propertyMap->second);
141 }
142 }
143 }
144
145 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500146 * @brief Returns the target speed value
147 */
148 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500149
Matthew Barth177fe982020-05-26 11:05:19 -0500150 /**
151 * @brief Returns the input speed value
152 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500153 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500154 {
155 return _tachInput;
156 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500157
Matthew Barth177fe982020-05-26 11:05:19 -0500158 /**
159 * @brief Returns true if sensor has a target
160 */
161 inline bool hasTarget() const
162 {
163 return _hasTarget;
164 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500165
Matthew Barth177fe982020-05-26 11:05:19 -0500166 /**
167 * @brief Returns the interface of the sensor target
168 */
169 inline std::string getInterface() const
170 {
171 return _interface;
172 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500173
Matthew Barth177fe982020-05-26 11:05:19 -0500174 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400175 * @brief Returns true if sensor has a D-Bus owner
176 */
177 inline bool hasOwner() const
178 {
179 return _hasOwner;
180 }
181
182 /**
183 * @brief sets D-Bus owner status
184 *
185 * @param[in] val - new owner status
186 */
187 inline void setOwner(bool val)
188 {
189 _hasOwner = val;
190 }
191
192 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500193 * @brief Returns the factor of the sensor target
194 */
195 inline double getFactor() const
196 {
197 return _factor;
198 }
Lei YU80f271b2018-01-31 15:24:46 +0800199
Matthew Barth177fe982020-05-26 11:05:19 -0500200 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400201 * @brief Returns a reference to the sensor's Fan object
202 */
203 inline Fan& getFan() const
204 {
205 return _fan;
206 }
207
208 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500209 * @brief Returns the offset of the sensor target
210 */
211 inline int64_t getOffset() const
212 {
213 return _offset;
214 }
Lei YU8e5d1972018-01-26 17:14:00 +0800215
Matthew Barth177fe982020-05-26 11:05:19 -0500216 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800217 * @brief Returns the method of out of range
218 */
219 inline size_t getMethod() const
220 {
221 return _method;
222 }
223
224 /**
225 * @brief Returns the threshold of count method
226 */
227 inline size_t getThreshold() const
228 {
229 return _threshold;
230 }
231
232 /**
233 * Set the sensor faulted counter
234 */
235 void setCounter(bool count);
236
237 /**
238 * @brief Returns the sensor faulted count
239 */
240 inline size_t getCounter() const
241 {
242 return _counter;
243 }
244
245 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500246 * Returns true if the hardware behind this
247 * sensor is considered working OK/functional.
248 */
249 inline bool functional() const
250 {
251 return _functional;
252 }
Lei YU8e5d1972018-01-26 17:14:00 +0800253
Matthew Barth177fe982020-05-26 11:05:19 -0500254 /**
255 * Set the functional status and update inventory to match
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500256 *
257 * @param[in] functional - The new state
258 * @param[in] skipErrorTimer - If setting the sensor to
259 * nonfunctional, don't start the error timer.
Matthew Barth177fe982020-05-26 11:05:19 -0500260 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500261 void setFunctional(bool functional, bool skipErrorTimer = false);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500262
Matthew Barth177fe982020-05-26 11:05:19 -0500263 /**
264 * @brief Says if the timer is running or not
265 *
266 * @return bool - if timer is currently running
267 */
268 inline bool timerRunning()
269 {
270 return _timer.isEnabled();
271 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500272
Matthew Barth177fe982020-05-26 11:05:19 -0500273 /**
274 * @brief Stops the timer when the given mode differs and starts
275 * the associated timer for the mode given if not already running
276 *
277 * @param[in] mode - mode of timer to start
278 */
279 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500280
Matthew Barth177fe982020-05-26 11:05:19 -0500281 /**
282 * @brief Stops the timer
283 */
284 inline void stopTimer()
285 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000286 lg2::debug("Stop running timer on tach sensor {NAME}.", "NAME", _name);
Matthew Barth177fe982020-05-26 11:05:19 -0500287 _timer.setEnabled(false);
288 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500289
Matthew Barth177fe982020-05-26 11:05:19 -0500290 /**
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600291 * @brief Says if the count timer is running
292 *
293 * @return bool - If count timer running
294 */
295 inline bool countTimerRunning() const
296 {
297 return _countTimer && _countTimer->isEnabled();
298 }
299
300 /**
301 * @brief Stops the count timer
302 */
303 void stopCountTimer();
304
305 /**
306 * @brief Starts the count timer
307 */
308 void startCountTimer();
309
310 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500311 * @brief Return the given timer mode's delay time
312 *
313 * @param[in] mode - mode of timer to get delay time for
314 */
315 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500316
Matthew Barth177fe982020-05-26 11:05:19 -0500317 /**
318 * Returns the sensor name
319 */
320 inline const std::string& name() const
321 {
322 return _name;
323 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500324
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500325 /**
326 * @brief Says if the error timer is running
327 *
328 * @return bool - If the timer is running
329 */
330 bool errorTimerRunning() const
331 {
332 if (_errorTimer && _errorTimer->isEnabled())
333 {
334 return true;
335 }
336 return false;
337 }
338
Matthew Barth7c23a042021-01-26 16:21:45 -0600339 /**
340 * @brief Get the current allowed range of speeds
341 *
Matt Spinlerf724c162023-05-10 11:14:37 -0500342 * @param[in] lowerDeviation - The configured lower deviation(in percent)
343 * allowed
344 * @param[in] upperDeviation - The configured upper deviation(in percent)
345 * allowed
Matthew Barth7c23a042021-01-26 16:21:45 -0600346 *
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 */
Patrick Williamsdfddd642024-08-16 15:21:51 -0400349 std::pair<uint64_t, std::optional<uint64_t>> getRange(
350 const size_t lowerDeviation, const size_t upperDeviation) 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 */
Chau Ly27cc39f2022-09-20 08:16:56 +0000389 std::string getMatchString(const std::optional<std::string> path,
390 const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500391
Matthew Barth177fe982020-05-26 11:05:19 -0500392 /**
393 * @brief Reads the Target property and stores in _tachTarget.
394 * Also calls Fan::tachChanged().
395 *
396 * @param[in] msg - the dbus message
397 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500398 void handleTargetChange(sdbusplus::message_t& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500399
Matthew Barth177fe982020-05-26 11:05:19 -0500400 /**
401 * @brief Reads the Value property and stores in _tachInput.
402 * Also calls Fan::tachChanged().
403 *
404 * @param[in] msg - the dbus message
405 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500406 void handleTachChange(sdbusplus::message_t& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500407
Matthew Barth177fe982020-05-26 11:05:19 -0500408 /**
409 * @brief Updates the Functional property in the inventory
410 * for this tach sensor based on the value passed in.
411 *
412 * @param[in] functional - If the Functional property should
413 * be set to true or false.
414 */
415 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500416
Matthew Barth177fe982020-05-26 11:05:19 -0500417 /**
418 * @brief the dbus object
419 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500420 sdbusplus::bus_t& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500421
Matthew Barth177fe982020-05-26 11:05:19 -0500422 /**
423 * @brief Reference to the parent Fan object
424 */
425 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500426
Matthew Barth177fe982020-05-26 11:05:19 -0500427 /**
428 * @brief The name of the sensor, including the full path
429 *
430 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
431 */
432 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500433
Matthew Barth177fe982020-05-26 11:05:19 -0500434 /**
435 * @brief The inventory name of the sensor, including the full path
436 */
437 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500438
Matthew Barth177fe982020-05-26 11:05:19 -0500439 /**
440 * @brief If functional (not too slow). The parent
441 * fan object sets this.
442 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500443 bool _functional = true;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500444
Matthew Barth177fe982020-05-26 11:05:19 -0500445 /**
446 * @brief If the sensor has a Target property (can set speed)
447 */
448 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600449
Matthew Barth177fe982020-05-26 11:05:19 -0500450 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400451 * @brief If the sensor has a D-Bus owner
452 */
453 bool _hasOwner = true;
454
455 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500456 * @brief Amount of time to delay updating to functional
457 */
458 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500459
Matthew Barth177fe982020-05-26 11:05:19 -0500460 /**
461 * @brief The interface that the target implements
462 */
463 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500464
Matthew Barth177fe982020-05-26 11:05:19 -0500465 /**
Chau Ly27cc39f2022-09-20 08:16:56 +0000466 * @brief The object path to set sensor's target
467 */
468 const std::string _path;
469
470 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500471 * @brief The factor of target to get fan rpm
472 */
473 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600474
Matthew Barth177fe982020-05-26 11:05:19 -0500475 /**
476 * @brief The offset of target to get fan rpm
477 */
478 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800479
Matthew Barth177fe982020-05-26 11:05:19 -0500480 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800481 * @brief The method of out of range
482 */
483 const size_t _method;
484
485 /**
486 * @brief The threshold for count method
487 */
488 const size_t _threshold;
489
490 /**
Matthew Barth8a8aa442021-11-19 14:13:13 -0600491 * @brief Whether to ignore being above the max or not
492 */
493 const bool _ignoreAboveMax;
494
495 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800496 * @brief The counter for count method
497 */
498 size_t _counter = 0;
499
500 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500501 * @brief The input speed, from the Value dbus property
502 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500503 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800504
Matthew Barth177fe982020-05-26 11:05:19 -0500505 /**
506 * @brief The current target speed, from the Target dbus property
507 * (if applicable)
508 */
509 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800510
Matthew Barth177fe982020-05-26 11:05:19 -0500511 /**
512 * @brief The timeout value to use
513 */
514 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500515
Matthew Barth177fe982020-05-26 11:05:19 -0500516 /**
517 * @brief Mode that current timer is in
518 */
519 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500520
Matthew Barth177fe982020-05-26 11:05:19 -0500521 /**
522 * The timer object
523 */
524 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500525
Matthew Barth177fe982020-05-26 11:05:19 -0500526 /**
527 * @brief The match object for the Value properties changed signal
528 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600529 std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600530
Matthew Barth177fe982020-05-26 11:05:19 -0500531 /**
532 * @brief The match object for the Target properties changed signal
533 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600534 std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500535
536 /**
537 * @brief The number of seconds to wait between a sensor being set
538 * to nonfunctional and creating an error for it.
539 *
540 * If std::nullopt, no errors will be created.
541 */
542 const std::optional<size_t> _errorDelay;
543
544 /**
545 * @brief The timer that uses _errorDelay. When it expires an error
546 * will be created for a faulted fan sensor (rotor).
547 *
548 * If _errorDelay is std::nullopt, then this won't be created.
549 */
550 std::unique_ptr<
551 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
552 _errorTimer;
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600553
554 /**
555 * @brief The interval, in seconds, to use for the timer that runs
556 * the checks when using the 'count' method.
557 */
558 size_t _countInterval;
559
560 /**
561 * @brief The timer used by the 'count' method for determining
562 * functional status.
563 */
564 std::unique_ptr<
565 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
566 _countTimer;
Mike Capps7b34ee02022-05-04 14:16:12 -0400567
568 /**
569 * @brief record of previous targets
570 */
571 std::deque<uint64_t> _prevTargets;
572
573 /**
574 * @brief record of previous tach readings
575 */
576 std::deque<uint64_t> _prevTachs;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500577};
578
Matthew Barth177fe982020-05-26 11:05:19 -0500579} // namespace monitor
580} // namespace fan
581} // namespace phosphor