1 #pragma once 2 3 #include <fmt/format.h> 4 5 #include <phosphor-logging/log.hpp> 6 #include <sdbusplus/bus.hpp> 7 #include <sdbusplus/bus/match.hpp> 8 #include <sdeventplus/clock.hpp> 9 #include <sdeventplus/event.hpp> 10 #include <sdeventplus/utility/timer.hpp> 11 12 #include <chrono> 13 #include <deque> 14 #include <optional> 15 #include <utility> 16 17 namespace phosphor 18 { 19 namespace fan 20 { 21 namespace monitor 22 { 23 24 class Fan; 25 26 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/"; 27 28 /** 29 * The mode fan monitor will run in: 30 * - init - only do the initialization steps 31 * - monitor - run normal monitoring algorithm 32 */ 33 enum class Mode 34 { 35 init, 36 monitor 37 }; 38 39 /** 40 * The mode that the timer is running in: 41 * - func - Transition to functional state timer 42 * - nonfunc - Transition to nonfunctional state timer 43 */ 44 enum class TimerMode 45 { 46 func, 47 nonfunc 48 }; 49 50 /** 51 * The mode that the method is running in: 52 * - time - Use a percentage based deviation 53 * - count - Run up/down count fault detection 54 */ 55 enum MethodMode 56 { 57 timebased = 0, 58 count 59 }; 60 61 /** 62 * @class TachSensor 63 * 64 * This class represents the sensor that reads a tach value. 65 * It may also support a Target, which is the property used to 66 * set a speed. Since it doesn't necessarily have a Target, it 67 * won't for sure know if it is running too slow, so it leaves 68 * that determination to other code. 69 * 70 * This class has a parent Fan object that knows about all 71 * sensors for that fan. 72 */ 73 class TachSensor 74 { 75 public: 76 TachSensor() = delete; 77 TachSensor(const TachSensor&) = delete; 78 // TachSensor is not moveable since the this pointer is used as systemd 79 // callback context. 80 TachSensor(TachSensor&&) = delete; 81 TachSensor& operator=(const TachSensor&) = delete; 82 TachSensor& operator=(TachSensor&&) = delete; 83 ~TachSensor() = default; 84 85 /** 86 * @brief Constructor 87 * 88 * @param[in] mode - mode of fan monitor 89 * @param[in] bus - the dbus object 90 * @param[in] fan - the parent fan object 91 * @param[in] id - the id of the sensor 92 * @param[in] hasTarget - if the sensor supports 93 * setting the speed 94 * @param[in] funcDelay - Delay to mark functional 95 * @param[in] interface - the interface of the target 96 * @param[in] factor - the factor of the sensor target 97 * @param[in] offset - the offset of the sensor target 98 * @param[in] method - the method of out of range 99 * @param[in] threshold - the threshold of counter method 100 * @param[in] ignoreAboveMax - whether to ignore being above max or not 101 * @param[in] timeout - Normal timeout value to use 102 * @param[in] errorDelay - Delay in seconds before creating an error 103 * or std::nullopt if no errors. 104 * @param[in] countInterval - In count mode interval 105 * 106 * @param[in] event - Event loop reference 107 */ 108 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan, 109 const std::string& id, bool hasTarget, size_t funcDelay, 110 const std::string& interface, double factor, int64_t offset, 111 size_t method, size_t threshold, bool ignoreAboveMax, 112 size_t timeout, const std::optional<size_t>& errorDelay, 113 size_t countInterval, 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> 127 static void readPropertyFromMessage(sdbusplus::message::message& msg, 128 const std::string& interface, 129 const std::string& propertyName, 130 T& value) 131 { 132 std::string sensor; 133 std::map<std::string, std::variant<T>> data; 134 msg.read(sensor, data); 135 136 if (sensor.compare(interface) == 0) 137 { 138 auto propertyMap = data.find(propertyName); 139 if (propertyMap != data.end()) 140 { 141 value = std::get<T>(propertyMap->second); 142 } 143 } 144 } 145 146 /** 147 * @brief Returns the target speed value 148 */ 149 uint64_t getTarget() const; 150 151 /** 152 * @brief Returns the input speed value 153 */ 154 inline double getInput() const 155 { 156 return _tachInput; 157 } 158 159 /** 160 * @brief Returns true if sensor has a target 161 */ 162 inline bool hasTarget() const 163 { 164 return _hasTarget; 165 } 166 167 /** 168 * @brief Returns the interface of the sensor target 169 */ 170 inline std::string getInterface() const 171 { 172 return _interface; 173 } 174 175 /** 176 * @brief Returns true if sensor has a D-Bus owner 177 */ 178 inline bool hasOwner() const 179 { 180 return _hasOwner; 181 } 182 183 /** 184 * @brief sets D-Bus owner status 185 * 186 * @param[in] val - new owner status 187 */ 188 inline void setOwner(bool val) 189 { 190 _hasOwner = val; 191 } 192 193 /** 194 * @brief Returns the factor of the sensor target 195 */ 196 inline double getFactor() const 197 { 198 return _factor; 199 } 200 201 /** 202 * @brief Returns a reference to the sensor's Fan object 203 */ 204 inline Fan& getFan() const 205 { 206 return _fan; 207 } 208 209 /** 210 * @brief Returns the offset of the sensor target 211 */ 212 inline int64_t getOffset() const 213 { 214 return _offset; 215 } 216 217 /** 218 * @brief Returns the method of out of range 219 */ 220 inline size_t getMethod() const 221 { 222 return _method; 223 } 224 225 /** 226 * @brief Returns the threshold of count method 227 */ 228 inline size_t getThreshold() const 229 { 230 return _threshold; 231 } 232 233 /** 234 * Set the sensor faulted counter 235 */ 236 void setCounter(bool count); 237 238 /** 239 * @brief Returns the sensor faulted count 240 */ 241 inline size_t getCounter() const 242 { 243 return _counter; 244 } 245 246 /** 247 * Returns true if the hardware behind this 248 * sensor is considered working OK/functional. 249 */ 250 inline bool functional() const 251 { 252 return _functional; 253 } 254 255 /** 256 * Set the functional status and update inventory to match 257 */ 258 void setFunctional(bool functional); 259 260 /** 261 * @brief Says if the timer is running or not 262 * 263 * @return bool - if timer is currently running 264 */ 265 inline bool timerRunning() 266 { 267 return _timer.isEnabled(); 268 } 269 270 /** 271 * @brief Stops the timer when the given mode differs and starts 272 * the associated timer for the mode given if not already running 273 * 274 * @param[in] mode - mode of timer to start 275 */ 276 void startTimer(TimerMode mode); 277 278 /** 279 * @brief Stops the timer 280 */ 281 inline void stopTimer() 282 { 283 phosphor::logging::log<phosphor::logging::level::DEBUG>( 284 fmt::format("Stop running timer on tach sensor {}.", _name) 285 .c_str()); 286 _timer.setEnabled(false); 287 } 288 289 /** 290 * @brief Says if the count timer is running 291 * 292 * @return bool - If count timer running 293 */ 294 inline bool countTimerRunning() const 295 { 296 return _countTimer && _countTimer->isEnabled(); 297 } 298 299 /** 300 * @brief Stops the count timer 301 */ 302 void stopCountTimer(); 303 304 /** 305 * @brief Starts the count timer 306 */ 307 void startCountTimer(); 308 309 /** 310 * @brief Return the given timer mode's delay time 311 * 312 * @param[in] mode - mode of timer to get delay time for 313 */ 314 std::chrono::microseconds getDelay(TimerMode mode); 315 316 /** 317 * Returns the sensor name 318 */ 319 inline const std::string& name() const 320 { 321 return _name; 322 }; 323 324 /** 325 * @brief Says if the error timer is running 326 * 327 * @return bool - If the timer is running 328 */ 329 bool errorTimerRunning() const 330 { 331 if (_errorTimer && _errorTimer->isEnabled()) 332 { 333 return true; 334 } 335 return false; 336 } 337 338 /** 339 * @brief Get the current allowed range of speeds 340 * 341 * @param[in] deviation - The configured deviation(in percent) allowed 342 * 343 * @return pair - Min/Max(optional) range of speeds allowed 344 */ 345 std::pair<uint64_t, std::optional<uint64_t>> 346 getRange(const size_t deviation) const; 347 348 /** 349 * @brief Processes the current state of the sensor 350 */ 351 void processState(); 352 353 /** 354 * @brief Resets the monitoring method of the sensor 355 */ 356 void resetMethod(); 357 358 /** 359 * @brief Refreshes the tach input and target values by 360 * reading them from D-Bus. 361 */ 362 void updateTachAndTarget(); 363 364 /** 365 * @brief return the previous tach values 366 */ 367 const std::deque<uint64_t>& getPrevTach() const 368 { 369 return _prevTachs; 370 } 371 372 /** 373 * @brief return the previous target values 374 */ 375 const std::deque<uint64_t>& getPrevTarget() const 376 { 377 return _prevTargets; 378 } 379 380 private: 381 /** 382 * @brief Returns the match string to use for matching 383 * on a properties changed signal. 384 */ 385 std::string getMatchString(const std::string& interface); 386 387 /** 388 * @brief Reads the Target property and stores in _tachTarget. 389 * Also calls Fan::tachChanged(). 390 * 391 * @param[in] msg - the dbus message 392 */ 393 void handleTargetChange(sdbusplus::message::message& msg); 394 395 /** 396 * @brief Reads the Value property and stores in _tachInput. 397 * Also calls Fan::tachChanged(). 398 * 399 * @param[in] msg - the dbus message 400 */ 401 void handleTachChange(sdbusplus::message::message& msg); 402 403 /** 404 * @brief Updates the Functional property in the inventory 405 * for this tach sensor based on the value passed in. 406 * 407 * @param[in] functional - If the Functional property should 408 * be set to true or false. 409 */ 410 void updateInventory(bool functional); 411 412 /** 413 * @brief the dbus object 414 */ 415 sdbusplus::bus::bus& _bus; 416 417 /** 418 * @brief Reference to the parent Fan object 419 */ 420 Fan& _fan; 421 422 /** 423 * @brief The name of the sensor, including the full path 424 * 425 * For example /xyz/openbmc_project/sensors/fan_tach/fan0 426 */ 427 const std::string _name; 428 429 /** 430 * @brief The inventory name of the sensor, including the full path 431 */ 432 const std::string _invName; 433 434 /** 435 * @brief If functional (not too slow). The parent 436 * fan object sets this. 437 */ 438 bool _functional; 439 440 /** 441 * @brief If the sensor has a Target property (can set speed) 442 */ 443 const bool _hasTarget; 444 445 /** 446 * @brief If the sensor has a D-Bus owner 447 */ 448 bool _hasOwner = true; 449 450 /** 451 * @brief Amount of time to delay updating to functional 452 */ 453 const size_t _funcDelay; 454 455 /** 456 * @brief The interface that the target implements 457 */ 458 const std::string _interface; 459 460 /** 461 * @brief The factor of target to get fan rpm 462 */ 463 const double _factor; 464 465 /** 466 * @brief The offset of target to get fan rpm 467 */ 468 const int64_t _offset; 469 470 /** 471 * @brief The method of out of range 472 */ 473 const size_t _method; 474 475 /** 476 * @brief The threshold for count method 477 */ 478 const size_t _threshold; 479 480 /** 481 * @brief Whether to ignore being above the max or not 482 */ 483 const bool _ignoreAboveMax; 484 485 /** 486 * @brief The counter for count method 487 */ 488 size_t _counter = 0; 489 490 /** 491 * @brief The input speed, from the Value dbus property 492 */ 493 double _tachInput = 0; 494 495 /** 496 * @brief The current target speed, from the Target dbus property 497 * (if applicable) 498 */ 499 uint64_t _tachTarget = 0; 500 501 /** 502 * @brief The timeout value to use 503 */ 504 const size_t _timeout; 505 506 /** 507 * @brief Mode that current timer is in 508 */ 509 TimerMode _timerMode; 510 511 /** 512 * The timer object 513 */ 514 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 515 516 /** 517 * @brief The match object for the Value properties changed signal 518 */ 519 std::unique_ptr<sdbusplus::bus::match_t> tachSignal; 520 521 /** 522 * @brief The match object for the Target properties changed signal 523 */ 524 std::unique_ptr<sdbusplus::bus::match_t> targetSignal; 525 526 /** 527 * @brief The number of seconds to wait between a sensor being set 528 * to nonfunctional and creating an error for it. 529 * 530 * If std::nullopt, no errors will be created. 531 */ 532 const std::optional<size_t> _errorDelay; 533 534 /** 535 * @brief The timer that uses _errorDelay. When it expires an error 536 * will be created for a faulted fan sensor (rotor). 537 * 538 * If _errorDelay is std::nullopt, then this won't be created. 539 */ 540 std::unique_ptr< 541 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 542 _errorTimer; 543 544 /** 545 * @brief The interval, in seconds, to use for the timer that runs 546 * the checks when using the 'count' method. 547 */ 548 size_t _countInterval; 549 550 /** 551 * @brief The timer used by the 'count' method for determining 552 * functional status. 553 */ 554 std::unique_ptr< 555 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 556 _countTimer; 557 558 /** 559 * @brief record of previous targets 560 */ 561 std::deque<uint64_t> _prevTargets; 562 563 /** 564 * @brief record of previous tach readings 565 */ 566 std::deque<uint64_t> _prevTachs; 567 }; 568 569 } // namespace monitor 570 } // namespace fan 571 } // namespace phosphor 572