blob: 4a09f171adcd8d33575490212dc95ef66407df08 [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001#pragma once
2
Matt Spinlerabf8da32017-04-27 14:08:45 -05003#include <sdbusplus/bus.hpp>
4#include <sdbusplus/server.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07005#include <sdeventplus/clock.hpp>
William A. Kennington III1cfc2f12018-10-19 17:29:46 -07006#include <sdeventplus/event.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -07007#include <sdeventplus/utility/timer.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -05008
Matthew Barth177fe982020-05-26 11:05:19 -05009#include <chrono>
Matthew Barth7c23a042021-01-26 16:21:45 -060010#include <utility>
Matthew Barth177fe982020-05-26 11:05:19 -050011
Matt Spinlerabf8da32017-04-27 14:08:45 -050012namespace phosphor
13{
14namespace fan
15{
16namespace monitor
17{
18
19class Fan;
20
Matt Spinler78689dd2017-09-28 10:12:07 -050021constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
Matt Spinlerabf8da32017-04-27 14:08:45 -050022
23/**
Matthew Barth0a9fe162018-01-26 12:53:15 -060024 * The mode fan monitor will run in:
25 * - init - only do the initialization steps
26 * - monitor - run normal monitoring algorithm
27 */
28enum class Mode
29{
30 init,
31 monitor
32};
33
34/**
Matthew Barth3800ae72018-02-19 16:08:04 -060035 * The mode that the timer is running in:
36 * - func - Transition to functional state timer
37 * - nonfunc - Transition to nonfunctional state timer
38 */
39enum class TimerMode
40{
41 func,
42 nonfunc
43};
44
45/**
Jolie Ku69f2f482020-10-21 09:59:43 +080046 * The mode that the method is running in:
47 * - time - Use a percentage based deviation
48 * - count - Run up/down count fault detection
49 */
50enum MethodMode
51{
52 timebased = 0,
53 count
54};
55
56/**
Matt Spinlerabf8da32017-04-27 14:08:45 -050057 * @class TachSensor
58 *
59 * This class represents the sensor that reads a tach value.
60 * It may also support a Target, which is the property used to
61 * set a speed. Since it doesn't necessarily have a Target, it
62 * won't for sure know if it is running too slow, so it leaves
63 * that determination to other code.
64 *
65 * This class has a parent Fan object that knows about all
66 * sensors for that fan.
67 */
68class TachSensor
69{
Matthew Barth177fe982020-05-26 11:05:19 -050070 public:
71 TachSensor() = delete;
72 TachSensor(const TachSensor&) = delete;
73 // TachSensor is not moveable since the this pointer is used as systemd
74 // callback context.
75 TachSensor(TachSensor&&) = delete;
76 TachSensor& operator=(const TachSensor&) = delete;
77 TachSensor& operator=(TachSensor&&) = delete;
78 ~TachSensor() = default;
Matt Spinlerabf8da32017-04-27 14:08:45 -050079
Matthew Barth177fe982020-05-26 11:05:19 -050080 /**
81 * @brief Constructor
82 *
83 * @param[in] mode - mode of fan monitor
84 * @param[in] bus - the dbus object
85 * @param[in] fan - the parent fan object
86 * @param[in] id - the id of the sensor
87 * @param[in] hasTarget - if the sensor supports
88 * setting the speed
89 * @param[in] funcDelay - Delay to mark functional
90 * @param[in] interface - the interface of the target
91 * @param[in] factor - the factor of the sensor target
92 * @param[in] offset - the offset of the sensor target
Jolie Ku69f2f482020-10-21 09:59:43 +080093 * @param[in] method - the method of out of range
94 * @param[in] threshold - the threshold of counter method
Matthew Barth177fe982020-05-26 11:05:19 -050095 * @param[in] timeout - Normal timeout value to use
Matt Spinlerf13b42e2020-10-26 15:29:49 -050096 * @param[in] errorDelay - Delay in seconds before creating an error
97 * or std::nullopt if no errors.
98 *
Matthew Barth177fe982020-05-26 11:05:19 -050099 * @param[in] event - Event loop reference
100 */
101 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan,
102 const std::string& id, bool hasTarget, size_t funcDelay,
103 const std::string& interface, double factor, int64_t offset,
Jolie Ku69f2f482020-10-21 09:59:43 +0800104 size_t method, size_t threshold, size_t timeout,
105 const std::optional<size_t>& errorDelay,
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500106 const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500107
Matthew Barth177fe982020-05-26 11:05:19 -0500108 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600109 * @brief Reads a property from the input message and stores it in value.
110 * T is the value type.
111 *
112 * Note: This can only be called once per message.
113 *
114 * @param[in] msg - the dbus message that contains the data
115 * @param[in] interface - the interface the property is on
116 * @param[in] propertName - the name of the property
117 * @param[out] value - the value to store the property value in
118 */
119 template <typename T>
120 static void readPropertyFromMessage(sdbusplus::message::message& msg,
121 const std::string& interface,
122 const std::string& propertyName,
123 T& value)
124 {
125 std::string sensor;
126 std::map<std::string, std::variant<T>> data;
127 msg.read(sensor, data);
128
129 if (sensor.compare(interface) == 0)
130 {
131 auto propertyMap = data.find(propertyName);
132 if (propertyMap != data.end())
133 {
134 value = std::get<T>(propertyMap->second);
135 }
136 }
137 }
138
139 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500140 * @brief Returns the target speed value
141 */
142 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500143
Matthew Barth177fe982020-05-26 11:05:19 -0500144 /**
145 * @brief Returns the input speed value
146 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500147 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500148 {
149 return _tachInput;
150 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500151
Matthew Barth177fe982020-05-26 11:05:19 -0500152 /**
153 * @brief Returns true if sensor has a target
154 */
155 inline bool hasTarget() const
156 {
157 return _hasTarget;
158 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500159
Matthew Barth177fe982020-05-26 11:05:19 -0500160 /**
161 * @brief Returns the interface of the sensor target
162 */
163 inline std::string getInterface() const
164 {
165 return _interface;
166 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500167
Matthew Barth177fe982020-05-26 11:05:19 -0500168 /**
169 * @brief Returns the factor of the sensor target
170 */
171 inline double getFactor() const
172 {
173 return _factor;
174 }
Lei YU80f271b2018-01-31 15:24:46 +0800175
Matthew Barth177fe982020-05-26 11:05:19 -0500176 /**
177 * @brief Returns the offset of the sensor target
178 */
179 inline int64_t getOffset() const
180 {
181 return _offset;
182 }
Lei YU8e5d1972018-01-26 17:14:00 +0800183
Matthew Barth177fe982020-05-26 11:05:19 -0500184 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800185 * @brief Returns the method of out of range
186 */
187 inline size_t getMethod() const
188 {
189 return _method;
190 }
191
192 /**
193 * @brief Returns the threshold of count method
194 */
195 inline size_t getThreshold() const
196 {
197 return _threshold;
198 }
199
200 /**
201 * Set the sensor faulted counter
202 */
203 void setCounter(bool count);
204
205 /**
206 * @brief Returns the sensor faulted count
207 */
208 inline size_t getCounter() const
209 {
210 return _counter;
211 }
212
213 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500214 * Returns true if the hardware behind this
215 * sensor is considered working OK/functional.
216 */
217 inline bool functional() const
218 {
219 return _functional;
220 }
Lei YU8e5d1972018-01-26 17:14:00 +0800221
Matthew Barth177fe982020-05-26 11:05:19 -0500222 /**
223 * Set the functional status and update inventory to match
224 */
225 void setFunctional(bool functional);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500226
Matthew Barth177fe982020-05-26 11:05:19 -0500227 /**
228 * @brief Says if the timer is running or not
229 *
230 * @return bool - if timer is currently running
231 */
232 inline bool timerRunning()
233 {
234 return _timer.isEnabled();
235 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500236
Matthew Barth177fe982020-05-26 11:05:19 -0500237 /**
238 * @brief Stops the timer when the given mode differs and starts
239 * the associated timer for the mode given if not already running
240 *
241 * @param[in] mode - mode of timer to start
242 */
243 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500244
Matthew Barth177fe982020-05-26 11:05:19 -0500245 /**
246 * @brief Stops the timer
247 */
248 inline void stopTimer()
249 {
250 _timer.setEnabled(false);
251 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500252
Matthew Barth177fe982020-05-26 11:05:19 -0500253 /**
254 * @brief Return the given timer mode's delay time
255 *
256 * @param[in] mode - mode of timer to get delay time for
257 */
258 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500259
Matthew Barth177fe982020-05-26 11:05:19 -0500260 /**
261 * Returns the sensor name
262 */
263 inline const std::string& name() const
264 {
265 return _name;
266 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500267
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500268 /**
269 * @brief Says if the error timer is running
270 *
271 * @return bool - If the timer is running
272 */
273 bool errorTimerRunning() const
274 {
275 if (_errorTimer && _errorTimer->isEnabled())
276 {
277 return true;
278 }
279 return false;
280 }
281
Matthew Barth7c23a042021-01-26 16:21:45 -0600282 /**
283 * @brief Get the current allowed range of speeds
284 *
285 * @param[in] deviation - The configured deviation(in percent) allowed
286 *
287 * @return pair - Min/Max range of speeds allowed
288 */
289 std::pair<uint64_t, uint64_t> getRange(const size_t deviation) const;
290
Matthew Barth177fe982020-05-26 11:05:19 -0500291 private:
292 /**
293 * @brief Returns the match string to use for matching
294 * on a properties changed signal.
295 */
296 std::string getMatchString(const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500297
Matthew Barth177fe982020-05-26 11:05:19 -0500298 /**
299 * @brief Reads the Target property and stores in _tachTarget.
300 * Also calls Fan::tachChanged().
301 *
302 * @param[in] msg - the dbus message
303 */
304 void handleTargetChange(sdbusplus::message::message& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500305
Matthew Barth177fe982020-05-26 11:05:19 -0500306 /**
307 * @brief Reads the Value property and stores in _tachInput.
308 * Also calls Fan::tachChanged().
309 *
310 * @param[in] msg - the dbus message
311 */
312 void handleTachChange(sdbusplus::message::message& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500313
Matthew Barth177fe982020-05-26 11:05:19 -0500314 /**
315 * @brief Updates the Functional property in the inventory
316 * for this tach sensor based on the value passed in.
317 *
318 * @param[in] functional - If the Functional property should
319 * be set to true or false.
320 */
321 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500322
Matthew Barth177fe982020-05-26 11:05:19 -0500323 /**
324 * @brief the dbus object
325 */
326 sdbusplus::bus::bus& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500327
Matthew Barth177fe982020-05-26 11:05:19 -0500328 /**
329 * @brief Reference to the parent Fan object
330 */
331 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500332
Matthew Barth177fe982020-05-26 11:05:19 -0500333 /**
334 * @brief The name of the sensor, including the full path
335 *
336 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
337 */
338 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500339
Matthew Barth177fe982020-05-26 11:05:19 -0500340 /**
341 * @brief The inventory name of the sensor, including the full path
342 */
343 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500344
Matthew Barth177fe982020-05-26 11:05:19 -0500345 /**
346 * @brief If functional (not too slow). The parent
347 * fan object sets this.
348 */
349 bool _functional;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500350
Matthew Barth177fe982020-05-26 11:05:19 -0500351 /**
352 * @brief If the sensor has a Target property (can set speed)
353 */
354 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600355
Matthew Barth177fe982020-05-26 11:05:19 -0500356 /**
357 * @brief Amount of time to delay updating to functional
358 */
359 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500360
Matthew Barth177fe982020-05-26 11:05:19 -0500361 /**
362 * @brief The interface that the target implements
363 */
364 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500365
Matthew Barth177fe982020-05-26 11:05:19 -0500366 /**
367 * @brief The factor of target to get fan rpm
368 */
369 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600370
Matthew Barth177fe982020-05-26 11:05:19 -0500371 /**
372 * @brief The offset of target to get fan rpm
373 */
374 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800375
Matthew Barth177fe982020-05-26 11:05:19 -0500376 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800377 * @brief The method of out of range
378 */
379 const size_t _method;
380
381 /**
382 * @brief The threshold for count method
383 */
384 const size_t _threshold;
385
386 /**
387 * @brief The counter for count method
388 */
389 size_t _counter = 0;
390
391 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500392 * @brief The input speed, from the Value dbus property
393 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500394 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800395
Matthew Barth177fe982020-05-26 11:05:19 -0500396 /**
397 * @brief The current target speed, from the Target dbus property
398 * (if applicable)
399 */
400 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800401
Matthew Barth177fe982020-05-26 11:05:19 -0500402 /**
403 * @brief The timeout value to use
404 */
405 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500406
Matthew Barth177fe982020-05-26 11:05:19 -0500407 /**
408 * @brief Mode that current timer is in
409 */
410 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500411
Matthew Barth177fe982020-05-26 11:05:19 -0500412 /**
413 * The timer object
414 */
415 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500416
Matthew Barth177fe982020-05-26 11:05:19 -0500417 /**
418 * @brief The match object for the Value properties changed signal
419 */
420 std::unique_ptr<sdbusplus::server::match::match> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600421
Matthew Barth177fe982020-05-26 11:05:19 -0500422 /**
423 * @brief The match object for the Target properties changed signal
424 */
425 std::unique_ptr<sdbusplus::server::match::match> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500426
427 /**
428 * @brief The number of seconds to wait between a sensor being set
429 * to nonfunctional and creating an error for it.
430 *
431 * If std::nullopt, no errors will be created.
432 */
433 const std::optional<size_t> _errorDelay;
434
435 /**
436 * @brief The timer that uses _errorDelay. When it expires an error
437 * will be created for a faulted fan sensor (rotor).
438 *
439 * If _errorDelay is std::nullopt, then this won't be created.
440 */
441 std::unique_ptr<
442 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
443 _errorTimer;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500444};
445
Matthew Barth177fe982020-05-26 11:05:19 -0500446} // namespace monitor
447} // namespace fan
448} // namespace phosphor