blob: 703605afa84313c789b4a2a6af911426ff6f7661 [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>
7#include <sdbusplus/server.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.
101 *
Matthew Barth177fe982020-05-26 11:05:19 -0500102 * @param[in] event - Event loop reference
103 */
104 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan,
105 const std::string& id, bool hasTarget, size_t funcDelay,
106 const std::string& interface, double factor, int64_t offset,
Jolie Ku69f2f482020-10-21 09:59:43 +0800107 size_t method, size_t threshold, size_t timeout,
108 const std::optional<size_t>& errorDelay,
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500109 const sdeventplus::Event& event);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500110
Matthew Barth177fe982020-05-26 11:05:19 -0500111 /**
Matthew Barthc8c8ccf2021-01-26 14:55:22 -0600112 * @brief Reads a property from the input message and stores it in value.
113 * T is the value type.
114 *
115 * Note: This can only be called once per message.
116 *
117 * @param[in] msg - the dbus message that contains the data
118 * @param[in] interface - the interface the property is on
119 * @param[in] propertName - the name of the property
120 * @param[out] value - the value to store the property value in
121 */
122 template <typename T>
123 static void readPropertyFromMessage(sdbusplus::message::message& msg,
124 const std::string& interface,
125 const std::string& propertyName,
126 T& value)
127 {
128 std::string sensor;
129 std::map<std::string, std::variant<T>> data;
130 msg.read(sensor, data);
131
132 if (sensor.compare(interface) == 0)
133 {
134 auto propertyMap = data.find(propertyName);
135 if (propertyMap != data.end())
136 {
137 value = std::get<T>(propertyMap->second);
138 }
139 }
140 }
141
142 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500143 * @brief Returns the target speed value
144 */
145 uint64_t getTarget() const;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500146
Matthew Barth177fe982020-05-26 11:05:19 -0500147 /**
148 * @brief Returns the input speed value
149 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500150 inline double getInput() const
Matthew Barth177fe982020-05-26 11:05:19 -0500151 {
152 return _tachInput;
153 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500154
Matthew Barth177fe982020-05-26 11:05:19 -0500155 /**
156 * @brief Returns true if sensor has a target
157 */
158 inline bool hasTarget() const
159 {
160 return _hasTarget;
161 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500162
Matthew Barth177fe982020-05-26 11:05:19 -0500163 /**
164 * @brief Returns the interface of the sensor target
165 */
166 inline std::string getInterface() const
167 {
168 return _interface;
169 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500170
Matthew Barth177fe982020-05-26 11:05:19 -0500171 /**
172 * @brief Returns the factor of the sensor target
173 */
174 inline double getFactor() const
175 {
176 return _factor;
177 }
Lei YU80f271b2018-01-31 15:24:46 +0800178
Matthew Barth177fe982020-05-26 11:05:19 -0500179 /**
180 * @brief Returns the offset of the sensor target
181 */
182 inline int64_t getOffset() const
183 {
184 return _offset;
185 }
Lei YU8e5d1972018-01-26 17:14:00 +0800186
Matthew Barth177fe982020-05-26 11:05:19 -0500187 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800188 * @brief Returns the method of out of range
189 */
190 inline size_t getMethod() const
191 {
192 return _method;
193 }
194
195 /**
196 * @brief Returns the threshold of count method
197 */
198 inline size_t getThreshold() const
199 {
200 return _threshold;
201 }
202
203 /**
204 * Set the sensor faulted counter
205 */
206 void setCounter(bool count);
207
208 /**
209 * @brief Returns the sensor faulted count
210 */
211 inline size_t getCounter() const
212 {
213 return _counter;
214 }
215
216 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500217 * Returns true if the hardware behind this
218 * sensor is considered working OK/functional.
219 */
220 inline bool functional() const
221 {
222 return _functional;
223 }
Lei YU8e5d1972018-01-26 17:14:00 +0800224
Matthew Barth177fe982020-05-26 11:05:19 -0500225 /**
226 * Set the functional status and update inventory to match
227 */
228 void setFunctional(bool functional);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500229
Matthew Barth177fe982020-05-26 11:05:19 -0500230 /**
231 * @brief Says if the timer is running or not
232 *
233 * @return bool - if timer is currently running
234 */
235 inline bool timerRunning()
236 {
237 return _timer.isEnabled();
238 }
Matt Spinlerabf8da32017-04-27 14:08:45 -0500239
Matthew Barth177fe982020-05-26 11:05:19 -0500240 /**
241 * @brief Stops the timer when the given mode differs and starts
242 * the associated timer for the mode given if not already running
243 *
244 * @param[in] mode - mode of timer to start
245 */
246 void startTimer(TimerMode mode);
Matt Spinler6fa181c2017-09-27 16:24:45 -0500247
Matthew Barth177fe982020-05-26 11:05:19 -0500248 /**
249 * @brief Stops the timer
250 */
251 inline void stopTimer()
252 {
Matthew Barth0d0e3552021-01-27 12:31:28 -0600253 phosphor::logging::log<phosphor::logging::level::INFO>(
254 fmt::format("Stop running timer on tach sensor {}.", _name)
255 .c_str());
Matthew Barth177fe982020-05-26 11:05:19 -0500256 _timer.setEnabled(false);
257 }
Matt Spinler6fa181c2017-09-27 16:24:45 -0500258
Matthew Barth177fe982020-05-26 11:05:19 -0500259 /**
260 * @brief Return the given timer mode's delay time
261 *
262 * @param[in] mode - mode of timer to get delay time for
263 */
264 std::chrono::microseconds getDelay(TimerMode mode);
Matt Spinlera9406a72017-04-27 14:29:24 -0500265
Matthew Barth177fe982020-05-26 11:05:19 -0500266 /**
267 * Returns the sensor name
268 */
269 inline const std::string& name() const
270 {
271 return _name;
272 };
Matt Spinlera9406a72017-04-27 14:29:24 -0500273
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500274 /**
275 * @brief Says if the error timer is running
276 *
277 * @return bool - If the timer is running
278 */
279 bool errorTimerRunning() const
280 {
281 if (_errorTimer && _errorTimer->isEnabled())
282 {
283 return true;
284 }
285 return false;
286 }
287
Matthew Barth7c23a042021-01-26 16:21:45 -0600288 /**
289 * @brief Get the current allowed range of speeds
290 *
291 * @param[in] deviation - The configured deviation(in percent) allowed
292 *
293 * @return pair - Min/Max range of speeds allowed
294 */
295 std::pair<uint64_t, uint64_t> getRange(const size_t deviation) const;
296
Matthew Barth177fe982020-05-26 11:05:19 -0500297 private:
298 /**
299 * @brief Returns the match string to use for matching
300 * on a properties changed signal.
301 */
302 std::string getMatchString(const std::string& interface);
Matt Spinlerce75b512017-07-26 15:10:48 -0500303
Matthew Barth177fe982020-05-26 11:05:19 -0500304 /**
305 * @brief Reads the Target property and stores in _tachTarget.
306 * Also calls Fan::tachChanged().
307 *
308 * @param[in] msg - the dbus message
309 */
310 void handleTargetChange(sdbusplus::message::message& msg);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500311
Matthew Barth177fe982020-05-26 11:05:19 -0500312 /**
313 * @brief Reads the Value property and stores in _tachInput.
314 * Also calls Fan::tachChanged().
315 *
316 * @param[in] msg - the dbus message
317 */
318 void handleTachChange(sdbusplus::message::message& msg);
Matt Spinlerebaae612017-04-27 14:21:48 -0500319
Matthew Barth177fe982020-05-26 11:05:19 -0500320 /**
321 * @brief Updates the Functional property in the inventory
322 * for this tach sensor based on the value passed in.
323 *
324 * @param[in] functional - If the Functional property should
325 * be set to true or false.
326 */
327 void updateInventory(bool functional);
Matt Spinlerebaae612017-04-27 14:21:48 -0500328
Matthew Barth177fe982020-05-26 11:05:19 -0500329 /**
330 * @brief the dbus object
331 */
332 sdbusplus::bus::bus& _bus;
Matt Spinlerebaae612017-04-27 14:21:48 -0500333
Matthew Barth177fe982020-05-26 11:05:19 -0500334 /**
335 * @brief Reference to the parent Fan object
336 */
337 Fan& _fan;
Matt Spinlerebaae612017-04-27 14:21:48 -0500338
Matthew Barth177fe982020-05-26 11:05:19 -0500339 /**
340 * @brief The name of the sensor, including the full path
341 *
342 * For example /xyz/openbmc_project/sensors/fan_tach/fan0
343 */
344 const std::string _name;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500345
Matthew Barth177fe982020-05-26 11:05:19 -0500346 /**
347 * @brief The inventory name of the sensor, including the full path
348 */
349 const std::string _invName;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500350
Matthew Barth177fe982020-05-26 11:05:19 -0500351 /**
352 * @brief If functional (not too slow). The parent
353 * fan object sets this.
354 */
355 bool _functional;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500356
Matthew Barth177fe982020-05-26 11:05:19 -0500357 /**
358 * @brief If the sensor has a Target property (can set speed)
359 */
360 const bool _hasTarget;
Matthew Barth4d982852017-11-17 09:37:13 -0600361
Matthew Barth177fe982020-05-26 11:05:19 -0500362 /**
363 * @brief Amount of time to delay updating to functional
364 */
365 const size_t _funcDelay;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500366
Matthew Barth177fe982020-05-26 11:05:19 -0500367 /**
368 * @brief The interface that the target implements
369 */
370 const std::string _interface;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500371
Matthew Barth177fe982020-05-26 11:05:19 -0500372 /**
373 * @brief The factor of target to get fan rpm
374 */
375 const double _factor;
Matthew Barth9396bcc2018-02-19 14:13:20 -0600376
Matthew Barth177fe982020-05-26 11:05:19 -0500377 /**
378 * @brief The offset of target to get fan rpm
379 */
380 const int64_t _offset;
Lei YU80f271b2018-01-31 15:24:46 +0800381
Matthew Barth177fe982020-05-26 11:05:19 -0500382 /**
Jolie Ku69f2f482020-10-21 09:59:43 +0800383 * @brief The method of out of range
384 */
385 const size_t _method;
386
387 /**
388 * @brief The threshold for count method
389 */
390 const size_t _threshold;
391
392 /**
393 * @brief The counter for count method
394 */
395 size_t _counter = 0;
396
397 /**
Matthew Barth177fe982020-05-26 11:05:19 -0500398 * @brief The input speed, from the Value dbus property
399 */
Matthew Barth0891e3b2020-08-13 12:00:23 -0500400 double _tachInput = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800401
Matthew Barth177fe982020-05-26 11:05:19 -0500402 /**
403 * @brief The current target speed, from the Target dbus property
404 * (if applicable)
405 */
406 uint64_t _tachTarget = 0;
Lei YU8e5d1972018-01-26 17:14:00 +0800407
Matthew Barth177fe982020-05-26 11:05:19 -0500408 /**
409 * @brief The timeout value to use
410 */
411 const size_t _timeout;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500412
Matthew Barth177fe982020-05-26 11:05:19 -0500413 /**
414 * @brief Mode that current timer is in
415 */
416 TimerMode _timerMode;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500417
Matthew Barth177fe982020-05-26 11:05:19 -0500418 /**
419 * The timer object
420 */
421 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
Matt Spinlerebaae612017-04-27 14:21:48 -0500422
Matthew Barth177fe982020-05-26 11:05:19 -0500423 /**
424 * @brief The match object for the Value properties changed signal
425 */
426 std::unique_ptr<sdbusplus::server::match::match> tachSignal;
Matthew Barth3800ae72018-02-19 16:08:04 -0600427
Matthew Barth177fe982020-05-26 11:05:19 -0500428 /**
429 * @brief The match object for the Target properties changed signal
430 */
431 std::unique_ptr<sdbusplus::server::match::match> targetSignal;
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500432
433 /**
434 * @brief The number of seconds to wait between a sensor being set
435 * to nonfunctional and creating an error for it.
436 *
437 * If std::nullopt, no errors will be created.
438 */
439 const std::optional<size_t> _errorDelay;
440
441 /**
442 * @brief The timer that uses _errorDelay. When it expires an error
443 * will be created for a faulted fan sensor (rotor).
444 *
445 * If _errorDelay is std::nullopt, then this won't be created.
446 */
447 std::unique_ptr<
448 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
449 _errorTimer;
Matt Spinlerabf8da32017-04-27 14:08:45 -0500450};
451
Matthew Barth177fe982020-05-26 11:05:19 -0500452} // namespace monitor
453} // namespace fan
454} // namespace phosphor