xref: /openbmc/phosphor-fan-presence/monitor/tach_sensor.hpp (revision a00f683cea5d288e2996a4b20abe3fb20d59f716)
1 #pragma once
2 
3 #include <phosphor-logging/lg2.hpp>
4 #include <sdbusplus/bus.hpp>
5 #include <sdbusplus/bus/match.hpp>
6 #include <sdeventplus/clock.hpp>
7 #include <sdeventplus/event.hpp>
8 #include <sdeventplus/utility/timer.hpp>
9 
10 #include <chrono>
11 #include <deque>
12 #include <optional>
13 #include <utility>
14 
15 namespace phosphor
16 {
17 namespace fan
18 {
19 namespace monitor
20 {
21 
22 class Fan;
23 
24 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
25 
26 /**
27  * The mode fan monitor will run in:
28  *   - init - only do the initialization steps
29  *   - monitor - run normal monitoring algorithm
30  */
31 enum class Mode
32 {
33     init,
34     monitor
35 };
36 
37 /**
38  * The mode that the timer is running in:
39  *   - func - Transition to functional state timer
40  *   - nonfunc - Transition to nonfunctional state timer
41  */
42 enum class TimerMode
43 {
44     func,
45     nonfunc
46 };
47 
48 /**
49  * The mode that the method is running in:
50  *   - time - Use a percentage based deviation
51  *   - count - Run up/down count fault detection
52  */
53 enum MethodMode
54 {
55     timebased = 0,
56     count
57 };
58 
59 /**
60  * @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  */
71 class TachSensor
72 {
73   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;
82 
83     /**
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] path - the object path of the sensor target
95      * @param[in] factor - the factor of the sensor target
96      * @param[in] offset - the offset of the sensor target
97      * @param[in] method - the method of out of range
98      * @param[in] threshold - the threshold of counter method
99      * @param[in] ignoreAboveMax - whether to ignore being above max or not
100      * @param[in] timeout - Normal timeout value to use
101      * @param[in] errorDelay - Delay in seconds before creating an error
102      *                         or std::nullopt if no errors.
103      * @param[in] countInterval - In count mode interval
104      *
105      * @param[in] event - Event loop reference
106      */
107     TachSensor(Mode mode, sdbusplus::bus_t& bus, Fan& fan,
108                const std::string& id, bool hasTarget, size_t funcDelay,
109                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);
114 
115     /**
116      * @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>
readPropertyFromMessage(sdbusplus::message_t & msg,const std::string & interface,const std::string & propertyName,T & value)127     static void readPropertyFromMessage(
128         sdbusplus::message_t& msg, const std::string& interface,
129         const std::string& propertyName, 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     /**
146      * @brief Returns the target speed value
147      */
148     uint64_t getTarget() const;
149 
150     /**
151      * @brief Returns the input speed value
152      */
getInput() const153     inline double getInput() const
154     {
155         return _tachInput;
156     }
157 
158     /**
159      * @brief Returns true if sensor has a target
160      */
hasTarget() const161     inline bool hasTarget() const
162     {
163         return _hasTarget;
164     }
165 
166     /**
167      * @brief Returns the interface of the sensor target
168      */
getInterface() const169     inline std::string getInterface() const
170     {
171         return _interface;
172     }
173 
174     /**
175      * @brief Returns true if sensor has a D-Bus owner
176      */
hasOwner() const177     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      */
setOwner(bool val)187     inline void setOwner(bool val)
188     {
189         _hasOwner = val;
190     }
191 
192     /**
193      * @brief Returns the factor of the sensor target
194      */
getFactor() const195     inline double getFactor() const
196     {
197         return _factor;
198     }
199 
200     /**
201      * @brief Returns a reference to the sensor's Fan object
202      */
getFan() const203     inline Fan& getFan() const
204     {
205         return _fan;
206     }
207 
208     /**
209      * @brief Returns the offset of the sensor target
210      */
getOffset() const211     inline int64_t getOffset() const
212     {
213         return _offset;
214     }
215 
216     /**
217      * @brief Returns the method of out of range
218      */
getMethod() const219     inline size_t getMethod() const
220     {
221         return _method;
222     }
223 
224     /**
225      * @brief Returns the threshold of count method
226      */
getThreshold() const227     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      */
getCounter() const240     inline size_t getCounter() const
241     {
242         return _counter;
243     }
244 
245     /**
246      * Returns true if the hardware behind this
247      * sensor is considered working OK/functional.
248      */
functional() const249     inline bool functional() const
250     {
251         return _functional;
252     }
253 
254     /**
255      * Set the functional status and update inventory to match
256      *
257      * @param[in] functional - The new state
258      * @param[in] skipErrorTimer - If setting the sensor to
259      *            nonfunctional, don't start the error timer.
260      */
261     void setFunctional(bool functional, bool skipErrorTimer = false);
262 
263     /**
264      * @brief Says if the timer is running or not
265      *
266      * @return bool - if timer is currently running
267      */
timerRunning()268     inline bool timerRunning()
269     {
270         return _timer.isEnabled();
271     }
272 
273     /**
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);
280 
281     /**
282      * @brief Stops the timer
283      */
stopTimer()284     inline void stopTimer()
285     {
286         lg2::debug("Stop running timer on tach sensor {NAME}.", "NAME", _name);
287         _timer.setEnabled(false);
288     }
289 
290     /**
291      * @brief Says if the count timer is running
292      *
293      * @return bool - If count timer running
294      */
countTimerRunning() const295     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     /**
311      * @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);
316 
317     /**
318      * Returns the sensor name
319      */
name() const320     inline const std::string& name() const
321     {
322         return _name;
323     };
324 
325     /**
326      * @brief Says if the error timer is running
327      *
328      * @return bool - If the timer is running
329      */
errorTimerRunning() const330     bool errorTimerRunning() const
331     {
332         if (_errorTimer && _errorTimer->isEnabled())
333         {
334             return true;
335         }
336         return false;
337     }
338 
339     /**
340      * @brief Get the current allowed range of speeds
341      *
342      * @param[in] lowerDeviation - The configured lower deviation(in percent)
343      *                             allowed
344      * @param[in] upperDeviation - The configured upper deviation(in percent)
345      *                             allowed
346      *
347      * @return pair - Min/Max(optional) range of speeds allowed
348      */
349     std::pair<uint64_t, std::optional<uint64_t>> getRange(
350         const size_t lowerDeviation, const size_t upperDeviation) const;
351 
352     /**
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 
362     /**
363      * @brief Refreshes the tach input and target values by
364      *        reading them from D-Bus.
365      */
366     void updateTachAndTarget();
367 
368     /**
369      * @brief return the previous tach values
370      */
getPrevTach() const371     const std::deque<uint64_t>& getPrevTach() const
372     {
373         return _prevTachs;
374     }
375 
376     /**
377      * @brief return the previous target values
378      */
getPrevTarget() const379     const std::deque<uint64_t>& getPrevTarget() const
380     {
381         return _prevTargets;
382     }
383 
384   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::optional<std::string> path,
390                                const std::string& interface);
391 
392     /**
393      * @brief Reads the Target property and stores in _tachTarget.
394      *        Also calls Fan::tachChanged().
395      *
396      * @param[in] msg - the dbus message
397      */
398     void handleTargetChange(sdbusplus::message_t& msg);
399 
400     /**
401      * @brief Reads the Value property and stores in _tachInput.
402      *        Also calls Fan::tachChanged().
403      *
404      * @param[in] msg - the dbus message
405      */
406     void handleTachChange(sdbusplus::message_t& msg);
407 
408     /**
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);
416 
417     /**
418      * @brief the dbus object
419      */
420     sdbusplus::bus_t& _bus;
421 
422     /**
423      * @brief Reference to the parent Fan object
424      */
425     Fan& _fan;
426 
427     /**
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;
433 
434     /**
435      * @brief The inventory name of the sensor, including the full path
436      */
437     const std::string _invName;
438 
439     /**
440      * @brief If functional (not too slow).  The parent
441      *        fan object sets this.
442      */
443     bool _functional = true;
444 
445     /**
446      * @brief If the sensor has a Target property (can set speed)
447      */
448     const bool _hasTarget;
449 
450     /**
451      * @brief If the sensor has a D-Bus owner
452      */
453     bool _hasOwner = true;
454 
455     /**
456      * @brief Amount of time to delay updating to functional
457      */
458     const size_t _funcDelay;
459 
460     /**
461      * @brief The interface that the target implements
462      */
463     const std::string _interface;
464 
465     /**
466      * @brief The object path to set sensor's target
467      */
468     const std::string _path;
469 
470     /**
471      * @brief The factor of target to get fan rpm
472      */
473     const double _factor;
474 
475     /**
476      * @brief The offset of target to get fan rpm
477      */
478     const int64_t _offset;
479 
480     /**
481      * @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     /**
491      * @brief Whether to ignore being above the max or not
492      */
493     const bool _ignoreAboveMax;
494 
495     /**
496      * @brief The counter for count method
497      */
498     size_t _counter = 0;
499 
500     /**
501      * @brief The input speed, from the Value dbus property
502      */
503     double _tachInput = 0;
504 
505     /**
506      * @brief The current target speed, from the Target dbus property
507      *        (if applicable)
508      */
509     uint64_t _tachTarget = 0;
510 
511     /**
512      * @brief The timeout value to use
513      */
514     const size_t _timeout;
515 
516     /**
517      * @brief Mode that current timer is in
518      */
519     TimerMode _timerMode;
520 
521     /**
522      * The timer object
523      */
524     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
525 
526     /**
527      * @brief The match object for the Value properties changed signal
528      */
529     std::unique_ptr<sdbusplus::bus::match_t> tachSignal;
530 
531     /**
532      * @brief The match object for the Target properties changed signal
533      */
534     std::unique_ptr<sdbusplus::bus::match_t> targetSignal;
535 
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;
553 
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;
567 
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;
577 };
578 
579 } // namespace monitor
580 } // namespace fan
581 } // namespace phosphor
582