1 #pragma once
2 
3 #include <sdbusplus/bus.hpp>
4 #include <sdbusplus/server.hpp>
5 #include <sdeventplus/clock.hpp>
6 #include <sdeventplus/event.hpp>
7 #include <sdeventplus/utility/timer.hpp>
8 
9 #include <chrono>
10 
11 namespace phosphor
12 {
13 namespace fan
14 {
15 namespace monitor
16 {
17 
18 class Fan;
19 
20 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
21 
22 /**
23  * The mode fan monitor will run in:
24  *   - init - only do the initialization steps
25  *   - monitor - run normal monitoring algorithm
26  */
27 enum class Mode
28 {
29     init,
30     monitor
31 };
32 
33 /**
34  * The mode that the timer is running in:
35  *   - func - Transition to functional state timer
36  *   - nonfunc - Transition to nonfunctional state timer
37  */
38 enum class TimerMode
39 {
40     func,
41     nonfunc
42 };
43 
44 /**
45  * @class TachSensor
46  *
47  * This class represents the sensor that reads a tach value.
48  * It may also support a Target, which is the property used to
49  * set a speed.  Since it doesn't necessarily have a Target, it
50  * won't for sure know if it is running too slow, so it leaves
51  * that determination to other code.
52  *
53  * This class has a parent Fan object that knows about all
54  * sensors for that fan.
55  */
56 class TachSensor
57 {
58   public:
59     TachSensor() = delete;
60     TachSensor(const TachSensor&) = delete;
61     // TachSensor is not moveable since the this pointer is used as systemd
62     // callback context.
63     TachSensor(TachSensor&&) = delete;
64     TachSensor& operator=(const TachSensor&) = delete;
65     TachSensor& operator=(TachSensor&&) = delete;
66     ~TachSensor() = default;
67 
68     /**
69      * @brief Constructor
70      *
71      * @param[in] mode - mode of fan monitor
72      * @param[in] bus - the dbus object
73      * @param[in] fan - the parent fan object
74      * @param[in] id - the id of the sensor
75      * @param[in] hasTarget - if the sensor supports
76      *                        setting the speed
77      * @param[in] funcDelay - Delay to mark functional
78      * @param[in] interface - the interface of the target
79      * @param[in] factor - the factor of the sensor target
80      * @param[in] offset - the offset of the sensor target
81      * @param[in] timeout - Normal timeout value to use
82      * @param[in] errorDelay - Delay in seconds before creating an error
83      *                         or std::nullopt if no errors.
84      *
85      * @param[in] event - Event loop reference
86      */
87     TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan,
88                const std::string& id, bool hasTarget, size_t funcDelay,
89                const std::string& interface, double factor, int64_t offset,
90                size_t timeout, const std::optional<size_t>& errorDelay,
91                const sdeventplus::Event& event);
92 
93     /**
94      * @brief Returns the target speed value
95      */
96     uint64_t getTarget() const;
97 
98     /**
99      * @brief Returns the input speed value
100      */
101     inline double getInput() const
102     {
103         return _tachInput;
104     }
105 
106     /**
107      * @brief Returns true if sensor has a target
108      */
109     inline bool hasTarget() const
110     {
111         return _hasTarget;
112     }
113 
114     /**
115      * @brief Returns the interface of the sensor target
116      */
117     inline std::string getInterface() const
118     {
119         return _interface;
120     }
121 
122     /**
123      * @brief Returns the factor of the sensor target
124      */
125     inline double getFactor() const
126     {
127         return _factor;
128     }
129 
130     /**
131      * @brief Returns the offset of the sensor target
132      */
133     inline int64_t getOffset() const
134     {
135         return _offset;
136     }
137 
138     /**
139      * Returns true if the hardware behind this
140      * sensor is considered working OK/functional.
141      */
142     inline bool functional() const
143     {
144         return _functional;
145     }
146 
147     /**
148      * Set the functional status and update inventory to match
149      */
150     void setFunctional(bool functional);
151 
152     /**
153      * @brief Says if the timer is running or not
154      *
155      * @return bool - if timer is currently running
156      */
157     inline bool timerRunning()
158     {
159         return _timer.isEnabled();
160     }
161 
162     /**
163      * @brief Stops the timer when the given mode differs and starts
164      * the associated timer for the mode given if not already running
165      *
166      * @param[in] mode - mode of timer to start
167      */
168     void startTimer(TimerMode mode);
169 
170     /**
171      * @brief Stops the timer
172      */
173     inline void stopTimer()
174     {
175         _timer.setEnabled(false);
176     }
177 
178     /**
179      * @brief Return the given timer mode's delay time
180      *
181      * @param[in] mode - mode of timer to get delay time for
182      */
183     std::chrono::microseconds getDelay(TimerMode mode);
184 
185     /**
186      * Returns the sensor name
187      */
188     inline const std::string& name() const
189     {
190         return _name;
191     };
192 
193     /**
194      * @brief Says if the error timer is running
195      *
196      * @return bool - If the timer is running
197      */
198     bool errorTimerRunning() const
199     {
200         if (_errorTimer && _errorTimer->isEnabled())
201         {
202             return true;
203         }
204         return false;
205     }
206 
207   private:
208     /**
209      * @brief Returns the match string to use for matching
210      *        on a properties changed signal.
211      */
212     std::string getMatchString(const std::string& interface);
213 
214     /**
215      * @brief Reads the Target property and stores in _tachTarget.
216      *        Also calls Fan::tachChanged().
217      *
218      * @param[in] msg - the dbus message
219      */
220     void handleTargetChange(sdbusplus::message::message& msg);
221 
222     /**
223      * @brief Reads the Value property and stores in _tachInput.
224      *        Also calls Fan::tachChanged().
225      *
226      * @param[in] msg - the dbus message
227      */
228     void handleTachChange(sdbusplus::message::message& msg);
229 
230     /**
231      * @brief Updates the Functional property in the inventory
232      *        for this tach sensor based on the value passed in.
233      *
234      * @param[in] functional - If the Functional property should
235      *                         be set to true or false.
236      */
237     void updateInventory(bool functional);
238 
239     /**
240      * @brief the dbus object
241      */
242     sdbusplus::bus::bus& _bus;
243 
244     /**
245      * @brief Reference to the parent Fan object
246      */
247     Fan& _fan;
248 
249     /**
250      * @brief The name of the sensor, including the full path
251      *
252      * For example /xyz/openbmc_project/sensors/fan_tach/fan0
253      */
254     const std::string _name;
255 
256     /**
257      * @brief The inventory name of the sensor, including the full path
258      */
259     const std::string _invName;
260 
261     /**
262      * @brief If functional (not too slow).  The parent
263      *        fan object sets this.
264      */
265     bool _functional;
266 
267     /**
268      * @brief If the sensor has a Target property (can set speed)
269      */
270     const bool _hasTarget;
271 
272     /**
273      * @brief Amount of time to delay updating to functional
274      */
275     const size_t _funcDelay;
276 
277     /**
278      * @brief The interface that the target implements
279      */
280     const std::string _interface;
281 
282     /**
283      * @brief The factor of target to get fan rpm
284      */
285     const double _factor;
286 
287     /**
288      * @brief The offset of target to get fan rpm
289      */
290     const int64_t _offset;
291 
292     /**
293      * @brief The input speed, from the Value dbus property
294      */
295     double _tachInput = 0;
296 
297     /**
298      * @brief The current target speed, from the Target dbus property
299      *        (if applicable)
300      */
301     uint64_t _tachTarget = 0;
302 
303     /**
304      * @brief The timeout value to use
305      */
306     const size_t _timeout;
307 
308     /**
309      * @brief Mode that current timer is in
310      */
311     TimerMode _timerMode;
312 
313     /**
314      * The timer object
315      */
316     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
317 
318     /**
319      * @brief The match object for the Value properties changed signal
320      */
321     std::unique_ptr<sdbusplus::server::match::match> tachSignal;
322 
323     /**
324      * @brief The match object for the Target properties changed signal
325      */
326     std::unique_ptr<sdbusplus::server::match::match> targetSignal;
327 
328     /**
329      * @brief The number of seconds to wait between a sensor being set
330      *        to nonfunctional and creating an error for it.
331      *
332      * If std::nullopt, no errors will be created.
333      */
334     const std::optional<size_t> _errorDelay;
335 
336     /**
337      * @brief The timer that uses _errorDelay.  When it expires an error
338      *        will be created for a faulted fan sensor (rotor).
339      *
340      * If _errorDelay is std::nullopt, then this won't be created.
341      */
342     std::unique_ptr<
343         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
344         _errorTimer;
345 };
346 
347 } // namespace monitor
348 } // namespace fan
349 } // namespace phosphor
350