blob: 1468ab114dbcf081c14c4e0890aab476ceb19a4f [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001#pragma once
2
Matthew Barth0d0e3552021-01-27 12:31:28 -06003#include <phosphor-logging/log.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>
Patrick Williamsfbf47032023-07-17 12:27:34 -050012#include <format>
Matthew Barth8a8aa442021-11-19 14:13:13 -060013#include <optional>
Matthew Barth7c23a042021-01-26 16:21:45 -060014#include <utility>
Matthew Barth177fe982020-05-26 11:05:19 -050015
Matt Spinlerabf8da32017-04-27 14:08:45 -050016namespace phosphor
17{
18namespace fan
19{
20namespace monitor
21{
22
23class Fan;
24
Matt Spinler78689dd2017-09-28 10:12:07 -050025constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
Matt Spinlerabf8da32017-04-27 14:08:45 -050026
27/**
Matthew Barth0a9fe162018-01-26 12:53:15 -060028 * The mode fan monitor will run in:
29 * - init - only do the initialization steps
30 * - monitor - run normal monitoring algorithm
31 */
32enum class Mode
33{
34 init,
35 monitor
36};
37
38/**
Matthew Barth3800ae72018-02-19 16:08:04 -060039 * The mode that the timer is running in:
40 * - func - Transition to functional state timer
41 * - nonfunc - Transition to nonfunctional state timer
42 */
43enum class TimerMode
44{
45 func,
46 nonfunc
47};
48
49/**
Jolie Ku69f2f482020-10-21 09:59:43 +080050 * The mode that the method is running in:
51 * - time - Use a percentage based deviation
52 * - count - Run up/down count fault detection
53 */
54enum MethodMode
55{
56 timebased = 0,
57 count
58};
59
60/**
Matt Spinlerabf8da32017-04-27 14:08:45 -050061 * @class TachSensor
62 *
63 * This class represents the sensor that reads a tach value.
64 * It may also support a Target, which is the property used to
65 * set a speed. Since it doesn't necessarily have a Target, it
66 * won't for sure know if it is running too slow, so it leaves
67 * that determination to other code.
68 *
69 * This class has a parent Fan object that knows about all
70 * sensors for that fan.
71 */
72class TachSensor
73{
Matthew Barth177fe982020-05-26 11:05:19 -050074 public:
75 TachSensor() = delete;
76 TachSensor(const TachSensor&) = delete;
77 // TachSensor is not moveable since the this pointer is used as systemd
78 // callback context.
79 TachSensor(TachSensor&&) = delete;
80 TachSensor& operator=(const TachSensor&) = delete;
81 TachSensor& operator=(TachSensor&&) = delete;
82 ~TachSensor() = default;
Matt Spinlerabf8da32017-04-27 14:08:45 -050083
Matthew Barth177fe982020-05-26 11:05:19 -050084 /**
85 * @brief Constructor
86 *
87 * @param[in] mode - mode of fan monitor
88 * @param[in] bus - the dbus object
89 * @param[in] fan - the parent fan object
90 * @param[in] id - the id of the sensor
91 * @param[in] hasTarget - if the sensor supports
92 * setting the speed
93 * @param[in] funcDelay - Delay to mark functional
94 * @param[in] interface - the interface of the target
Chau Ly27cc39f2022-09-20 08:16:56 +000095 * @param[in] path - the object path of the sensor target
Matthew Barth177fe982020-05-26 11:05:19 -050096 * @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,
Chau Ly27cc39f2022-09-20 08:16:56 +0000110 const std::string& interface, const std::string& path,
111 double factor, int64_t offset, size_t method, size_t threshold,
112 bool ignoreAboveMax, size_t timeout,
113 const std::optional<size_t>& errorDelay, size_t countInterval,
114 const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500115
Matthew Barth177fe982020-05-26 11:05:19 -0500116 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600117 * @brief Reads a property from the input message and stores it in value.
118 * T is the value type.
119 *
120 * Note: This can only be called once per message.
121 *
122 * @param[in] msg - the dbus message that contains the data
123 * @param[in] interface - the interface the property is on
124 * @param[in] propertName - the name of the property
125 * @param[out] value - the value to store the property value in
126 */
127 template <typename T>
Patrick Williamscb356d42022-07-22 19:26:53 -0500128 static void readPropertyFromMessage(sdbusplus::message_t& msg,
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600129 const std::string& interface,
130 const std::string& propertyName,
131 T& value)
132 {
133 std::string sensor;
134 std::map<std::string, std::variant<T>> data;
135 msg.read(sensor, data);
136
137 if (sensor.compare(interface) == 0)
138 {
139 auto propertyMap = data.find(propertyName);
140 if (propertyMap != data.end())
141 {
142 value = std::get<T>(propertyMap->second);
143 }
144 }
145 }
146
147 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500148 * @brief Returns the target speed value
149 */
150 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500151
Matthew Barth177fe982020-05-26 11:05:19 -0500152 /**
153 * @brief Returns the input speed value
154 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500155 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500156 {
157 return _tachInput;
158 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500159
Matthew Barth177fe982020-05-26 11:05:19 -0500160 /**
161 * @brief Returns true if sensor has a target
162 */
163 inline bool hasTarget() const
164 {
165 return _hasTarget;
166 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500167
Matthew Barth177fe982020-05-26 11:05:19 -0500168 /**
169 * @brief Returns the interface of the sensor target
170 */
171 inline std::string getInterface() const
172 {
173 return _interface;
174 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500175
Matthew Barth177fe982020-05-26 11:05:19 -0500176 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400177 * @brief Returns true if sensor has a D-Bus owner
178 */
179 inline bool hasOwner() const
180 {
181 return _hasOwner;
182 }
183
184 /**
185 * @brief sets D-Bus owner status
186 *
187 * @param[in] val - new owner status
188 */
189 inline void setOwner(bool val)
190 {
191 _hasOwner = val;
192 }
193
194 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500195 * @brief Returns the factor of the sensor target
196 */
197 inline double getFactor() const
198 {
199 return _factor;
200 }
Lei YU80f271b2018-01-31 15:24:46 +0800201
Matthew Barth177fe982020-05-26 11:05:19 -0500202 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400203 * @brief Returns a reference to the sensor's Fan object
204 */
205 inline Fan& getFan() const
206 {
207 return _fan;
208 }
209
210 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500211 * @brief Returns the offset of the sensor target
212 */
213 inline int64_t getOffset() const
214 {
215 return _offset;
216 }
Lei YU8e5d1972018-01-26 17:14:00 +0800217
Matthew Barth177fe982020-05-26 11:05:19 -0500218 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800219 * @brief Returns the method of out of range
220 */
221 inline size_t getMethod() const
222 {
223 return _method;
224 }
225
226 /**
227 * @brief Returns the threshold of count method
228 */
229 inline size_t getThreshold() const
230 {
231 return _threshold;
232 }
233
234 /**
235 * Set the sensor faulted counter
236 */
237 void setCounter(bool count);
238
239 /**
240 * @brief Returns the sensor faulted count
241 */
242 inline size_t getCounter() const
243 {
244 return _counter;
245 }
246
247 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500248 * Returns true if the hardware behind this
249 * sensor is considered working OK/functional.
250 */
251 inline bool functional() const
252 {
253 return _functional;
254 }
Lei YU8e5d1972018-01-26 17:14:00 +0800255
Matthew Barth177fe982020-05-26 11:05:19 -0500256 /**
257 * Set the functional status and update inventory to match
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500258 *
259 * @param[in] functional - The new state
260 * @param[in] skipErrorTimer - If setting the sensor to
261 * nonfunctional, don't start the error timer.
Matthew Barth177fe982020-05-26 11:05:19 -0500262 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500263 void setFunctional(bool functional, bool skipErrorTimer = false);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500264
Matthew Barth177fe982020-05-26 11:05:19 -0500265 /**
266 * @brief Says if the timer is running or not
267 *
268 * @return bool - if timer is currently running
269 */
270 inline bool timerRunning()
271 {
272 return _timer.isEnabled();
273 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500274
Matthew Barth177fe982020-05-26 11:05:19 -0500275 /**
276 * @brief Stops the timer when the given mode differs and starts
277 * the associated timer for the mode given if not already running
278 *
279 * @param[in] mode - mode of timer to start
280 */
281 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500282
Matthew Barth177fe982020-05-26 11:05:19 -0500283 /**
284 * @brief Stops the timer
285 */
286 inline void stopTimer()
287 {
Matt Spinler1d7379e2021-03-01 16:16:17 -0600288 phosphor::logging::log<phosphor::logging::level::DEBUG>(
Patrick Williamsfbf47032023-07-17 12:27:34 -0500289 std::format("Stop running timer on tach sensor {}.", _name)
Matthew Barth0d0e3552021-01-27 12:31:28 -0600290 .c_str());
Matthew Barth177fe982020-05-26 11:05:19 -0500291 _timer.setEnabled(false);
292 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500293
Matthew Barth177fe982020-05-26 11:05:19 -0500294 /**
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600295 * @brief Says if the count timer is running
296 *
297 * @return bool - If count timer running
298 */
299 inline bool countTimerRunning() const
300 {
301 return _countTimer && _countTimer->isEnabled();
302 }
303
304 /**
305 * @brief Stops the count timer
306 */
307 void stopCountTimer();
308
309 /**
310 * @brief Starts the count timer
311 */
312 void startCountTimer();
313
314 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500315 * @brief Return the given timer mode's delay time
316 *
317 * @param[in] mode - mode of timer to get delay time for
318 */
319 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500320
Matthew Barth177fe982020-05-26 11:05:19 -0500321 /**
322 * Returns the sensor name
323 */
324 inline const std::string& name() const
325 {
326 return _name;
327 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500328
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500329 /**
330 * @brief Says if the error timer is running
331 *
332 * @return bool - If the timer is running
333 */
334 bool errorTimerRunning() const
335 {
336 if (_errorTimer && _errorTimer->isEnabled())
337 {
338 return true;
339 }
340 return false;
341 }
342
Matthew Barth7c23a042021-01-26 16:21:45 -0600343 /**
344 * @brief Get the current allowed range of speeds
345 *
Matt Spinlerf724c162023-05-10 11:14:37 -0500346 * @param[in] lowerDeviation - The configured lower deviation(in percent)
347 * allowed
348 * @param[in] upperDeviation - The configured upper deviation(in percent)
349 * allowed
Matthew Barth7c23a042021-01-26 16:21:45 -0600350 *
Matthew Barth8a8aa442021-11-19 14:13:13 -0600351 * @return pair - Min/Max(optional) range of speeds allowed
Matthew Barth7c23a042021-01-26 16:21:45 -0600352 */
Matthew Barth8a8aa442021-11-19 14:13:13 -0600353 std::pair<uint64_t, std::optional<uint64_t>>
Matt Spinlerf724c162023-05-10 11:14:37 -0500354 getRange(const size_t lowerDeviation,
355 const size_t upperDeviation) const;
Matthew Barth7c23a042021-01-26 16:21:45 -0600356
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600357 /**
358 * @brief Processes the current state of the sensor
359 */
360 void processState();
361
362 /**
363 * @brief Resets the monitoring method of the sensor
364 */
365 void resetMethod();
366
Matt Spinler4283c5d2021-03-01 15:56:00 -0600367 /**
368 * @brief Refreshes the tach input and target values by
369 * reading them from D-Bus.
370 */
371 void updateTachAndTarget();
372
Mike Capps7b34ee02022-05-04 14:16:12 -0400373 /**
374 * @brief return the previous tach values
375 */
376 const std::deque<uint64_t>& getPrevTach() const
377 {
378 return _prevTachs;
379 }
380
381 /**
382 * @brief return the previous target values
383 */
384 const std::deque<uint64_t>& getPrevTarget() const
385 {
386 return _prevTargets;
387 }
388
Matthew Barth177fe982020-05-26 11:05:19 -0500389 private:
390 /**
391 * @brief Returns the match string to use for matching
392 * on a properties changed signal.
393 */
Chau Ly27cc39f2022-09-20 08:16:56 +0000394 std::string getMatchString(const std::optional<std::string> path,
395 const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500396
Matthew Barth177fe982020-05-26 11:05:19 -0500397 /**
398 * @brief Reads the Target property and stores in _tachTarget.
399 * Also calls Fan::tachChanged().
400 *
401 * @param[in] msg - the dbus message
402 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500403 void handleTargetChange(sdbusplus::message_t& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500404
Matthew Barth177fe982020-05-26 11:05:19 -0500405 /**
406 * @brief Reads the Value property and stores in _tachInput.
407 * Also calls Fan::tachChanged().
408 *
409 * @param[in] msg - the dbus message
410 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500411 void handleTachChange(sdbusplus::message_t& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500412
Matthew Barth177fe982020-05-26 11:05:19 -0500413 /**
414 * @brief Updates the Functional property in the inventory
415 * for this tach sensor based on the value passed in.
416 *
417 * @param[in] functional - If the Functional property should
418 * be set to true or false.
419 */
420 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500421
Matthew Barth177fe982020-05-26 11:05:19 -0500422 /**
423 * @brief the dbus object
424 */
Patrick Williamscb356d42022-07-22 19:26:53 -0500425 sdbusplus::bus_t& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500426
Matthew Barth177fe982020-05-26 11:05:19 -0500427 /**
428 * @brief Reference to the parent Fan object
429 */
430 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500431
Matthew Barth177fe982020-05-26 11:05:19 -0500432 /**
433 * @brief The name of the sensor, including the full path
434 *
435 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
436 */
437 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500438
Matthew Barth177fe982020-05-26 11:05:19 -0500439 /**
440 * @brief The inventory name of the sensor, including the full path
441 */
442 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500443
Matthew Barth177fe982020-05-26 11:05:19 -0500444 /**
445 * @brief If functional (not too slow). The parent
446 * fan object sets this.
447 */
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500448 bool _functional = true;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500449
Matthew Barth177fe982020-05-26 11:05:19 -0500450 /**
451 * @brief If the sensor has a Target property (can set speed)
452 */
453 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600454
Matthew Barth177fe982020-05-26 11:05:19 -0500455 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400456 * @brief If the sensor has a D-Bus owner
457 */
458 bool _hasOwner = true;
459
460 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500461 * @brief Amount of time to delay updating to functional
462 */
463 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500464
Matthew Barth177fe982020-05-26 11:05:19 -0500465 /**
466 * @brief The interface that the target implements
467 */
468 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500469
Matthew Barth177fe982020-05-26 11:05:19 -0500470 /**
Chau Ly27cc39f2022-09-20 08:16:56 +0000471 * @brief The object path to set sensor's target
472 */
473 const std::string _path;
474
475 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500476 * @brief The factor of target to get fan rpm
477 */
478 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600479
Matthew Barth177fe982020-05-26 11:05:19 -0500480 /**
481 * @brief The offset of target to get fan rpm
482 */
483 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800484
Matthew Barth177fe982020-05-26 11:05:19 -0500485 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800486 * @brief The method of out of range
487 */
488 const size_t _method;
489
490 /**
491 * @brief The threshold for count method
492 */
493 const size_t _threshold;
494
495 /**
Matthew Barth8a8aa442021-11-19 14:13:13 -0600496 * @brief Whether to ignore being above the max or not
497 */
498 const bool _ignoreAboveMax;
499
500 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800501 * @brief The counter for count method
502 */
503 size_t _counter = 0;
504
505 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500506 * @brief The input speed, from the Value dbus property
507 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500508 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800509
Matthew Barth177fe982020-05-26 11:05:19 -0500510 /**
511 * @brief The current target speed, from the Target dbus property
512 * (if applicable)
513 */
514 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800515
Matthew Barth177fe982020-05-26 11:05:19 -0500516 /**
517 * @brief The timeout value to use
518 */
519 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500520
Matthew Barth177fe982020-05-26 11:05:19 -0500521 /**
522 * @brief Mode that current timer is in
523 */
524 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500525
Matthew Barth177fe982020-05-26 11:05:19 -0500526 /**
527 * The timer object
528 */
529 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500530
Matthew Barth177fe982020-05-26 11:05:19 -0500531 /**
532 * @brief The match object for the Value properties changed signal
533 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600534 std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600535
Matthew Barth177fe982020-05-26 11:05:19 -0500536 /**
537 * @brief The match object for the Target properties changed signal
538 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600539 std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500540
541 /**
542 * @brief The number of seconds to wait between a sensor being set
543 * to nonfunctional and creating an error for it.
544 *
545 * If std::nullopt, no errors will be created.
546 */
547 const std::optional<size_t> _errorDelay;
548
549 /**
550 * @brief The timer that uses _errorDelay. When it expires an error
551 * will be created for a faulted fan sensor (rotor).
552 *
553 * If _errorDelay is std::nullopt, then this won't be created.
554 */
555 std::unique_ptr<
556 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
557 _errorTimer;
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600558
559 /**
560 * @brief The interval, in seconds, to use for the timer that runs
561 * the checks when using the 'count' method.
562 */
563 size_t _countInterval;
564
565 /**
566 * @brief The timer used by the 'count' method for determining
567 * functional status.
568 */
569 std::unique_ptr<
570 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
571 _countTimer;
Mike Capps7b34ee02022-05-04 14:16:12 -0400572
573 /**
574 * @brief record of previous targets
575 */
576 std::deque<uint64_t> _prevTargets;
577
578 /**
579 * @brief record of previous tach readings
580 */
581 std::deque<uint64_t> _prevTachs;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500582};
583
Matthew Barth177fe982020-05-26 11:05:19 -0500584} // namespace monitor
585} // namespace fan
586} // namespace phosphor