blob: dc8814fa751ff435e1e94f3f7f0abdc5f662562a [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 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
94 * @param[in] factor - the factor of the sensor target
95 * @param[in] offset - the offset of the sensor target
Jolie Ku69f2f482020-10-21 09:59:43 +080096 * @param[in] method - the method of out of range
97 * @param[in] threshold - the threshold of counter method
Matthew Barth177fe982020-05-26 11:05:19 -050098 * @param[in] timeout - Normal timeout value to use
Matt Spinlerf13b42e2020-10-26 15:29:49 -050099 * @param[in] errorDelay - Delay in seconds before creating an error
100 * or std::nullopt if no errors.
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600101 * @param[in] countInterval - In count mode interval
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500102 *
Matthew Barth177fe982020-05-26 11:05:19 -0500103 * @param[in] event - Event loop reference
104 */
105 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan,
106 const std::string& id, bool hasTarget, size_t funcDelay,
107 const std::string& interface, double factor, int64_t offset,
Jolie Ku69f2f482020-10-21 09:59:43 +0800108 size_t method, size_t threshold, size_t timeout,
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600109 const std::optional<size_t>& errorDelay, size_t countInterval,
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500110 const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500111
Matthew Barth177fe982020-05-26 11:05:19 -0500112 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600113 * @brief Reads a property from the input message and stores it in value.
114 * T is the value type.
115 *
116 * Note: This can only be called once per message.
117 *
118 * @param[in] msg - the dbus message that contains the data
119 * @param[in] interface - the interface the property is on
120 * @param[in] propertName - the name of the property
121 * @param[out] value - the value to store the property value in
122 */
123 template <typename T>
124 static void readPropertyFromMessage(sdbusplus::message::message& msg,
125 const std::string& interface,
126 const std::string& propertyName,
127 T& value)
128 {
129 std::string sensor;
130 std::map<std::string, std::variant<T>> data;
131 msg.read(sensor, data);
132
133 if (sensor.compare(interface) == 0)
134 {
135 auto propertyMap = data.find(propertyName);
136 if (propertyMap != data.end())
137 {
138 value = std::get<T>(propertyMap->second);
139 }
140 }
141 }
142
143 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500144 * @brief Returns the target speed value
145 */
146 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500147
Matthew Barth177fe982020-05-26 11:05:19 -0500148 /**
149 * @brief Returns the input speed value
150 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500151 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500152 {
153 return _tachInput;
154 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500155
Matthew Barth177fe982020-05-26 11:05:19 -0500156 /**
157 * @brief Returns true if sensor has a target
158 */
159 inline bool hasTarget() const
160 {
161 return _hasTarget;
162 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500163
Matthew Barth177fe982020-05-26 11:05:19 -0500164 /**
165 * @brief Returns the interface of the sensor target
166 */
167 inline std::string getInterface() const
168 {
169 return _interface;
170 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500171
Matthew Barth177fe982020-05-26 11:05:19 -0500172 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400173 * @brief Returns true if sensor has a D-Bus owner
174 */
175 inline bool hasOwner() const
176 {
177 return _hasOwner;
178 }
179
180 /**
181 * @brief sets D-Bus owner status
182 *
183 * @param[in] val - new owner status
184 */
185 inline void setOwner(bool val)
186 {
187 _hasOwner = val;
188 }
189
190 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500191 * @brief Returns the factor of the sensor target
192 */
193 inline double getFactor() const
194 {
195 return _factor;
196 }
Lei YU80f271b2018-01-31 15:24:46 +0800197
Matthew Barth177fe982020-05-26 11:05:19 -0500198 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400199 * @brief Returns a reference to the sensor's Fan object
200 */
201 inline Fan& getFan() const
202 {
203 return _fan;
204 }
205
206 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500207 * @brief Returns the offset of the sensor target
208 */
209 inline int64_t getOffset() const
210 {
211 return _offset;
212 }
Lei YU8e5d1972018-01-26 17:14:00 +0800213
Matthew Barth177fe982020-05-26 11:05:19 -0500214 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800215 * @brief Returns the method of out of range
216 */
217 inline size_t getMethod() const
218 {
219 return _method;
220 }
221
222 /**
223 * @brief Returns the threshold of count method
224 */
225 inline size_t getThreshold() const
226 {
227 return _threshold;
228 }
229
230 /**
231 * Set the sensor faulted counter
232 */
233 void setCounter(bool count);
234
235 /**
236 * @brief Returns the sensor faulted count
237 */
238 inline size_t getCounter() const
239 {
240 return _counter;
241 }
242
243 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500244 * Returns true if the hardware behind this
245 * sensor is considered working OK/functional.
246 */
247 inline bool functional() const
248 {
249 return _functional;
250 }
Lei YU8e5d1972018-01-26 17:14:00 +0800251
Matthew Barth177fe982020-05-26 11:05:19 -0500252 /**
253 * Set the functional status and update inventory to match
254 */
255 void setFunctional(bool functional);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500256
Matthew Barth177fe982020-05-26 11:05:19 -0500257 /**
258 * @brief Says if the timer is running or not
259 *
260 * @return bool - if timer is currently running
261 */
262 inline bool timerRunning()
263 {
264 return _timer.isEnabled();
265 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500266
Matthew Barth177fe982020-05-26 11:05:19 -0500267 /**
268 * @brief Stops the timer when the given mode differs and starts
269 * the associated timer for the mode given if not already running
270 *
271 * @param[in] mode - mode of timer to start
272 */
273 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500274
Matthew Barth177fe982020-05-26 11:05:19 -0500275 /**
276 * @brief Stops the timer
277 */
278 inline void stopTimer()
279 {
Matt Spinler1d7379e2021-03-01 16:16:17 -0600280 phosphor::logging::log<phosphor::logging::level::DEBUG>(
Matthew Barth0d0e3552021-01-27 12:31:28 -0600281 fmt::format("Stop running timer on tach sensor {}.", _name)
282 .c_str());
Matthew Barth177fe982020-05-26 11:05:19 -0500283 _timer.setEnabled(false);
284 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500285
Matthew Barth177fe982020-05-26 11:05:19 -0500286 /**
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600287 * @brief Says if the count timer is running
288 *
289 * @return bool - If count timer running
290 */
291 inline bool countTimerRunning() const
292 {
293 return _countTimer && _countTimer->isEnabled();
294 }
295
296 /**
297 * @brief Stops the count timer
298 */
299 void stopCountTimer();
300
301 /**
302 * @brief Starts the count timer
303 */
304 void startCountTimer();
305
306 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500307 * @brief Return the given timer mode's delay time
308 *
309 * @param[in] mode - mode of timer to get delay time for
310 */
311 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500312
Matthew Barth177fe982020-05-26 11:05:19 -0500313 /**
314 * Returns the sensor name
315 */
316 inline const std::string& name() const
317 {
318 return _name;
319 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500320
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500321 /**
322 * @brief Says if the error timer is running
323 *
324 * @return bool - If the timer is running
325 */
326 bool errorTimerRunning() const
327 {
328 if (_errorTimer && _errorTimer->isEnabled())
329 {
330 return true;
331 }
332 return false;
333 }
334
Matthew Barth7c23a042021-01-26 16:21:45 -0600335 /**
336 * @brief Get the current allowed range of speeds
337 *
338 * @param[in] deviation - The configured deviation(in percent) allowed
339 *
340 * @return pair - Min/Max range of speeds allowed
341 */
342 std::pair<uint64_t, uint64_t> getRange(const size_t deviation) const;
343
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600344 /**
345 * @brief Processes the current state of the sensor
346 */
347 void processState();
348
349 /**
350 * @brief Resets the monitoring method of the sensor
351 */
352 void resetMethod();
353
Matt Spinler4283c5d2021-03-01 15:56:00 -0600354 /**
355 * @brief Refreshes the tach input and target values by
356 * reading them from D-Bus.
357 */
358 void updateTachAndTarget();
359
Matthew Barth177fe982020-05-26 11:05:19 -0500360 private:
361 /**
362 * @brief Returns the match string to use for matching
363 * on a properties changed signal.
364 */
365 std::string getMatchString(const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500366
Matthew Barth177fe982020-05-26 11:05:19 -0500367 /**
368 * @brief Reads the Target property and stores in _tachTarget.
369 * Also calls Fan::tachChanged().
370 *
371 * @param[in] msg - the dbus message
372 */
373 void handleTargetChange(sdbusplus::message::message& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500374
Matthew Barth177fe982020-05-26 11:05:19 -0500375 /**
376 * @brief Reads the Value property and stores in _tachInput.
377 * Also calls Fan::tachChanged().
378 *
379 * @param[in] msg - the dbus message
380 */
381 void handleTachChange(sdbusplus::message::message& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500382
Matthew Barth177fe982020-05-26 11:05:19 -0500383 /**
384 * @brief Updates the Functional property in the inventory
385 * for this tach sensor based on the value passed in.
386 *
387 * @param[in] functional - If the Functional property should
388 * be set to true or false.
389 */
390 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500391
Matthew Barth177fe982020-05-26 11:05:19 -0500392 /**
393 * @brief the dbus object
394 */
395 sdbusplus::bus::bus& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500396
Matthew Barth177fe982020-05-26 11:05:19 -0500397 /**
398 * @brief Reference to the parent Fan object
399 */
400 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500401
Matthew Barth177fe982020-05-26 11:05:19 -0500402 /**
403 * @brief The name of the sensor, including the full path
404 *
405 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
406 */
407 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500408
Matthew Barth177fe982020-05-26 11:05:19 -0500409 /**
410 * @brief The inventory name of the sensor, including the full path
411 */
412 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500413
Matthew Barth177fe982020-05-26 11:05:19 -0500414 /**
415 * @brief If functional (not too slow). The parent
416 * fan object sets this.
417 */
418 bool _functional;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500419
Matthew Barth177fe982020-05-26 11:05:19 -0500420 /**
421 * @brief If the sensor has a Target property (can set speed)
422 */
423 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600424
Matthew Barth177fe982020-05-26 11:05:19 -0500425 /**
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400426 * @brief If the sensor has a D-Bus owner
427 */
428 bool _hasOwner = true;
429
430 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500431 * @brief Amount of time to delay updating to functional
432 */
433 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500434
Matthew Barth177fe982020-05-26 11:05:19 -0500435 /**
436 * @brief The interface that the target implements
437 */
438 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500439
Matthew Barth177fe982020-05-26 11:05:19 -0500440 /**
441 * @brief The factor of target to get fan rpm
442 */
443 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600444
Matthew Barth177fe982020-05-26 11:05:19 -0500445 /**
446 * @brief The offset of target to get fan rpm
447 */
448 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800449
Matthew Barth177fe982020-05-26 11:05:19 -0500450 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800451 * @brief The method of out of range
452 */
453 const size_t _method;
454
455 /**
456 * @brief The threshold for count method
457 */
458 const size_t _threshold;
459
460 /**
461 * @brief The counter for count method
462 */
463 size_t _counter = 0;
464
465 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500466 * @brief The input speed, from the Value dbus property
467 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500468 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800469
Matthew Barth177fe982020-05-26 11:05:19 -0500470 /**
471 * @brief The current target speed, from the Target dbus property
472 * (if applicable)
473 */
474 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800475
Matthew Barth177fe982020-05-26 11:05:19 -0500476 /**
477 * @brief The timeout value to use
478 */
479 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500480
Matthew Barth177fe982020-05-26 11:05:19 -0500481 /**
482 * @brief Mode that current timer is in
483 */
484 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500485
Matthew Barth177fe982020-05-26 11:05:19 -0500486 /**
487 * The timer object
488 */
489 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500490
Matthew Barth177fe982020-05-26 11:05:19 -0500491 /**
492 * @brief The match object for the Value properties changed signal
493 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600494 std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600495
Matthew Barth177fe982020-05-26 11:05:19 -0500496 /**
497 * @brief The match object for the Target properties changed signal
498 */
Patrick Williams3ea9ec22021-11-19 12:21:08 -0600499 std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500500
501 /**
502 * @brief The number of seconds to wait between a sensor being set
503 * to nonfunctional and creating an error for it.
504 *
505 * If std::nullopt, no errors will be created.
506 */
507 const std::optional<size_t> _errorDelay;
508
509 /**
510 * @brief The timer that uses _errorDelay. When it expires an error
511 * will be created for a faulted fan sensor (rotor).
512 *
513 * If _errorDelay is std::nullopt, then this won't be created.
514 */
515 std::unique_ptr<
516 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
517 _errorTimer;
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600518
519 /**
520 * @brief The interval, in seconds, to use for the timer that runs
521 * the checks when using the 'count' method.
522 */
523 size_t _countInterval;
524
525 /**
526 * @brief The timer used by the 'count' method for determining
527 * functional status.
528 */
529 std::unique_ptr<
530 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
531 _countTimer;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500532};
533
Matthew Barth177fe982020-05-26 11:05:19 -0500534} // namespace monitor
535} // namespace fan
536} // namespace phosphor