blob: 87c69ac76f52dd311d649268f245166fb14d04b3 [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>
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
95 * @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 */
107 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan,
108 const std::string& id, bool hasTarget, size_t funcDelay,
109 const std::string& interface, double factor, int64_t offset,
Matthew Barth8a8aa442021-11-19 14:13:13 -0600110 size_t method, size_t threshold, bool ignoreAboveMax,
111 size_t timeout, const std::optional<size_t>& errorDelay,
112 size_t countInterval, const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500113
Matthew Barth177fe982020-05-26 11:05:19 -0500114 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600115 * @brief Reads a property from the input message and stores it in value.
116 * T is the value type.
117 *
118 * Note: This can only be called once per message.
119 *
120 * @param[in] msg - the dbus message that contains the data
121 * @param[in] interface - the interface the property is on
122 * @param[in] propertName - the name of the property
123 * @param[out] value - the value to store the property value in
124 */
125 template <typename T>
126 static void readPropertyFromMessage(sdbusplus::message::message& msg,
127 const std::string& interface,
128 const std::string& propertyName,
129 T& value)
130 {
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
256 */
257 void setFunctional(bool functional);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500258
Matthew Barth177fe982020-05-26 11:05:19 -0500259 /**
260 * @brief Says if the timer is running or not
261 *
262 * @return bool - if timer is currently running
263 */
264 inline bool timerRunning()
265 {
266 return _timer.isEnabled();
267 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500268
Matthew Barth177fe982020-05-26 11:05:19 -0500269 /**
270 * @brief Stops the timer when the given mode differs and starts
271 * the associated timer for the mode given if not already running
272 *
273 * @param[in] mode - mode of timer to start
274 */
275 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500276
Matthew Barth177fe982020-05-26 11:05:19 -0500277 /**
278 * @brief Stops the timer
279 */
280 inline void stopTimer()
281 {
Matt Spinler1d7379e2021-03-01 16:16:17 -0600282 phosphor::logging::log<phosphor::logging::level::DEBUG>(
Matthew Barth0d0e3552021-01-27 12:31:28 -0600283 fmt::format("Stop running timer on tach sensor {}.", _name)
284 .c_str());
Matthew Barth177fe982020-05-26 11:05:19 -0500285 _timer.setEnabled(false);
286 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500287
Matthew Barth177fe982020-05-26 11:05:19 -0500288 /**
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600289 * @brief Says if the count timer is running
290 *
291 * @return bool - If count timer running
292 */
293 inline bool countTimerRunning() const
294 {
295 return _countTimer && _countTimer->isEnabled();
296 }
297
298 /**
299 * @brief Stops the count timer
300 */
301 void stopCountTimer();
302
303 /**
304 * @brief Starts the count timer
305 */
306 void startCountTimer();
307
308 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500309 * @brief Return the given timer mode's delay time
310 *
311 * @param[in] mode - mode of timer to get delay time for
312 */
313 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500314
Matthew Barth177fe982020-05-26 11:05:19 -0500315 /**
316 * Returns the sensor name
317 */
318 inline const std::string& name() const
319 {
320 return _name;
321 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500322
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500323 /**
324 * @brief Says if the error timer is running
325 *
326 * @return bool - If the timer is running
327 */
328 bool errorTimerRunning() const
329 {
330 if (_errorTimer && _errorTimer->isEnabled())
331 {
332 return true;
333 }
334 return false;
335 }
336
Matthew Barth7c23a042021-01-26 16:21:45 -0600337 /**
338 * @brief Get the current allowed range of speeds
339 *
340 * @param[in] deviation - The configured deviation(in percent) allowed
341 *
Matthew Barth8a8aa442021-11-19 14:13:13 -0600342 * @return pair - Min/Max(optional) range of speeds allowed
Matthew Barth7c23a042021-01-26 16:21:45 -0600343 */
Matthew Barth8a8aa442021-11-19 14:13:13 -0600344 std::pair<uint64_t, std::optional<uint64_t>>
345 getRange(const size_t deviation) const;
Matthew Barth7c23a042021-01-26 16:21:45 -0600346
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600347 /**
348 * @brief Processes the current state of the sensor
349 */
350 void processState();
351
352 /**
353 * @brief Resets the monitoring method of the sensor
354 */
355 void resetMethod();
356
Matt Spinler4283c5d2021-03-01 15:56:00 -0600357 /**
358 * @brief Refreshes the tach input and target values by
359 * reading them from D-Bus.
360 */
361 void updateTachAndTarget();
362
Matthew Barth177fe982020-05-26 11:05:19 -0500363 private:
364 /**
365 * @brief Returns the match string to use for matching
366 * on a properties changed signal.
367 */
368 std::string getMatchString(const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500369
Matthew Barth177fe982020-05-26 11:05:19 -0500370 /**
371 * @brief Reads the Target property and stores in _tachTarget.
372 * Also calls Fan::tachChanged().
373 *
374 * @param[in] msg - the dbus message
375 */
376 void handleTargetChange(sdbusplus::message::message& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500377
Matthew Barth177fe982020-05-26 11:05:19 -0500378 /**
379 * @brief Reads the Value property and stores in _tachInput.
380 * Also calls Fan::tachChanged().
381 *
382 * @param[in] msg - the dbus message
383 */
384 void handleTachChange(sdbusplus::message::message& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500385
Matthew Barth177fe982020-05-26 11:05:19 -0500386 /**
387 * @brief Updates the Functional property in the inventory
388 * for this tach sensor based on the value passed in.
389 *
390 * @param[in] functional - If the Functional property should
391 * be set to true or false.
392 */
393 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500394
Matthew Barth177fe982020-05-26 11:05:19 -0500395 /**
396 * @brief the dbus object
397 */
398 sdbusplus::bus::bus& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500399
Matthew Barth177fe982020-05-26 11:05:19 -0500400 /**
401 * @brief Reference to the parent Fan object
402 */
403 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500404
Matthew Barth177fe982020-05-26 11:05:19 -0500405 /**
406 * @brief The name of the sensor, including the full path
407 *
408 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
409 */
410 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500411
Matthew Barth177fe982020-05-26 11:05:19 -0500412 /**
413 * @brief The inventory name of the sensor, including the full path
414 */
415 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500416
Matthew Barth177fe982020-05-26 11:05:19 -0500417 /**
418 * @brief If functional (not too slow). The parent
419 * fan object sets this.
420 */
421 bool _functional;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500422
Matthew Barth177fe982020-05-26 11:05:19 -0500423 /**
424 * @brief If the sensor has a Target property (can set speed)
425 */
426 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600427
Matthew Barth177fe982020-05-26 11:05:19 -0500428 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400429 * @brief If the sensor has a D-Bus owner
430 */
431 bool _hasOwner = true;
432
433 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500434 * @brief Amount of time to delay updating to functional
435 */
436 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500437
Matthew Barth177fe982020-05-26 11:05:19 -0500438 /**
439 * @brief The interface that the target implements
440 */
441 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500442
Matthew Barth177fe982020-05-26 11:05:19 -0500443 /**
444 * @brief The factor of target to get fan rpm
445 */
446 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600447
Matthew Barth177fe982020-05-26 11:05:19 -0500448 /**
449 * @brief The offset of target to get fan rpm
450 */
451 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800452
Matthew Barth177fe982020-05-26 11:05:19 -0500453 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800454 * @brief The method of out of range
455 */
456 const size_t _method;
457
458 /**
459 * @brief The threshold for count method
460 */
461 const size_t _threshold;
462
463 /**
Matthew Barth8a8aa442021-11-19 14:13:13 -0600464 * @brief Whether to ignore being above the max or not
465 */
466 const bool _ignoreAboveMax;
467
468 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800469 * @brief The counter for count method
470 */
471 size_t _counter = 0;
472
473 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500474 * @brief The input speed, from the Value dbus property
475 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500476 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800477
Matthew Barth177fe982020-05-26 11:05:19 -0500478 /**
479 * @brief The current target speed, from the Target dbus property
480 * (if applicable)
481 */
482 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800483
Matthew Barth177fe982020-05-26 11:05:19 -0500484 /**
485 * @brief The timeout value to use
486 */
487 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500488
Matthew Barth177fe982020-05-26 11:05:19 -0500489 /**
490 * @brief Mode that current timer is in
491 */
492 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500493
Matthew Barth177fe982020-05-26 11:05:19 -0500494 /**
495 * The timer object
496 */
497 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500498
Matthew Barth177fe982020-05-26 11:05:19 -0500499 /**
500 * @brief The match object for the Value properties changed signal
501 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600502 std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600503
Matthew Barth177fe982020-05-26 11:05:19 -0500504 /**
505 * @brief The match object for the Target properties changed signal
506 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600507 std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500508
509 /**
510 * @brief The number of seconds to wait between a sensor being set
511 * to nonfunctional and creating an error for it.
512 *
513 * If std::nullopt, no errors will be created.
514 */
515 const std::optional<size_t> _errorDelay;
516
517 /**
518 * @brief The timer that uses _errorDelay. When it expires an error
519 * will be created for a faulted fan sensor (rotor).
520 *
521 * If _errorDelay is std::nullopt, then this won't be created.
522 */
523 std::unique_ptr<
524 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
525 _errorTimer;
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600526
527 /**
528 * @brief The interval, in seconds, to use for the timer that runs
529 * the checks when using the 'count' method.
530 */
531 size_t _countInterval;
532
533 /**
534 * @brief The timer used by the 'count' method for determining
535 * functional status.
536 */
537 std::unique_ptr<
538 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
539 _countTimer;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500540};
541
Matthew Barth177fe982020-05-26 11:05:19 -0500542} // namespace monitor
543} // namespace fan
544} // namespace phosphor