1 #pragma once 2 3 #include <fmt/format.h> 4 5 #include <phosphor-logging/log.hpp> 6 #include <sdbusplus/bus.hpp> 7 #include <sdbusplus/server.hpp> 8 #include <sdeventplus/clock.hpp> 9 #include <sdeventplus/event.hpp> 10 #include <sdeventplus/utility/timer.hpp> 11 12 #include <chrono> 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] factor - the factor of the sensor target 95 * @param[in] offset - the offset of the sensor target 96 * @param[in] method - the method of out of range 97 * @param[in] threshold - the threshold of counter method 98 * @param[in] timeout - Normal timeout value to use 99 * @param[in] errorDelay - Delay in seconds before creating an error 100 * or std::nullopt if no errors. 101 * @param[in] countInterval - In count mode interval 102 * 103 * @param[in] event - Event loop reference 104 */ 105 TachSensor(Mode mode, sdbusplus::bus::bus& bus, Fan& fan, 106 const std::string& id, bool hasTarget, size_t funcDelay, 107 const std::string& interface, double factor, int64_t offset, 108 size_t method, size_t threshold, size_t timeout, 109 const std::optional<size_t>& errorDelay, size_t countInterval, 110 const sdeventplus::Event& event); 111 112 /** 113 * @brief Reads a property from the input message and stores it in value. 114 * T is the value type. 115 * 116 * Note: This can only be called once per message. 117 * 118 * @param[in] msg - the dbus message that contains the data 119 * @param[in] interface - the interface the property is on 120 * @param[in] propertName - the name of the property 121 * @param[out] value - the value to store the property value in 122 */ 123 template <typename T> 124 static void readPropertyFromMessage(sdbusplus::message::message& msg, 125 const std::string& interface, 126 const std::string& propertyName, 127 T& value) 128 { 129 std::string sensor; 130 std::map<std::string, std::variant<T>> data; 131 msg.read(sensor, data); 132 133 if (sensor.compare(interface) == 0) 134 { 135 auto propertyMap = data.find(propertyName); 136 if (propertyMap != data.end()) 137 { 138 value = std::get<T>(propertyMap->second); 139 } 140 } 141 } 142 143 /** 144 * @brief Returns the target speed value 145 */ 146 uint64_t getTarget() const; 147 148 /** 149 * @brief Returns the input speed value 150 */ 151 inline double getInput() const 152 { 153 return _tachInput; 154 } 155 156 /** 157 * @brief Returns true if sensor has a target 158 */ 159 inline bool hasTarget() const 160 { 161 return _hasTarget; 162 } 163 164 /** 165 * @brief Returns the interface of the sensor target 166 */ 167 inline std::string getInterface() const 168 { 169 return _interface; 170 } 171 172 /** 173 * @brief Returns true if sensor has a D-Bus owner 174 */ 175 inline bool hasOwner() const 176 { 177 return _hasOwner; 178 } 179 180 /** 181 * @brief sets D-Bus owner status 182 * 183 * @param[in] val - new owner status 184 */ 185 inline void setOwner(bool val) 186 { 187 _hasOwner = val; 188 } 189 190 /** 191 * @brief Returns the factor of the sensor target 192 */ 193 inline double getFactor() const 194 { 195 return _factor; 196 } 197 198 /** 199 * @brief Returns a reference to the sensor's Fan object 200 */ 201 inline Fan& getFan() const 202 { 203 return _fan; 204 } 205 206 /** 207 * @brief Returns the offset of the sensor target 208 */ 209 inline int64_t getOffset() const 210 { 211 return _offset; 212 } 213 214 /** 215 * @brief Returns the method of out of range 216 */ 217 inline size_t getMethod() const 218 { 219 return _method; 220 } 221 222 /** 223 * @brief Returns the threshold of count method 224 */ 225 inline size_t getThreshold() const 226 { 227 return _threshold; 228 } 229 230 /** 231 * Set the sensor faulted counter 232 */ 233 void setCounter(bool count); 234 235 /** 236 * @brief Returns the sensor faulted count 237 */ 238 inline size_t getCounter() const 239 { 240 return _counter; 241 } 242 243 /** 244 * Returns true if the hardware behind this 245 * sensor is considered working OK/functional. 246 */ 247 inline bool functional() const 248 { 249 return _functional; 250 } 251 252 /** 253 * Set the functional status and update inventory to match 254 */ 255 void setFunctional(bool functional); 256 257 /** 258 * @brief Says if the timer is running or not 259 * 260 * @return bool - if timer is currently running 261 */ 262 inline bool timerRunning() 263 { 264 return _timer.isEnabled(); 265 } 266 267 /** 268 * @brief Stops the timer when the given mode differs and starts 269 * the associated timer for the mode given if not already running 270 * 271 * @param[in] mode - mode of timer to start 272 */ 273 void startTimer(TimerMode mode); 274 275 /** 276 * @brief Stops the timer 277 */ 278 inline void stopTimer() 279 { 280 phosphor::logging::log<phosphor::logging::level::DEBUG>( 281 fmt::format("Stop running timer on tach sensor {}.", _name) 282 .c_str()); 283 _timer.setEnabled(false); 284 } 285 286 /** 287 * @brief Says if the count timer is running 288 * 289 * @return bool - If count timer running 290 */ 291 inline bool countTimerRunning() const 292 { 293 return _countTimer && _countTimer->isEnabled(); 294 } 295 296 /** 297 * @brief Stops the count timer 298 */ 299 void stopCountTimer(); 300 301 /** 302 * @brief Starts the count timer 303 */ 304 void startCountTimer(); 305 306 /** 307 * @brief Return the given timer mode's delay time 308 * 309 * @param[in] mode - mode of timer to get delay time for 310 */ 311 std::chrono::microseconds getDelay(TimerMode mode); 312 313 /** 314 * Returns the sensor name 315 */ 316 inline const std::string& name() const 317 { 318 return _name; 319 }; 320 321 /** 322 * @brief Says if the error timer is running 323 * 324 * @return bool - If the timer is running 325 */ 326 bool errorTimerRunning() const 327 { 328 if (_errorTimer && _errorTimer->isEnabled()) 329 { 330 return true; 331 } 332 return false; 333 } 334 335 /** 336 * @brief Get the current allowed range of speeds 337 * 338 * @param[in] deviation - The configured deviation(in percent) allowed 339 * 340 * @return pair - Min/Max range of speeds allowed 341 */ 342 std::pair<uint64_t, uint64_t> getRange(const size_t deviation) const; 343 344 /** 345 * @brief Processes the current state of the sensor 346 */ 347 void processState(); 348 349 /** 350 * @brief Resets the monitoring method of the sensor 351 */ 352 void resetMethod(); 353 354 /** 355 * @brief Refreshes the tach input and target values by 356 * reading them from D-Bus. 357 */ 358 void updateTachAndTarget(); 359 360 private: 361 /** 362 * @brief Returns the match string to use for matching 363 * on a properties changed signal. 364 */ 365 std::string getMatchString(const std::string& interface); 366 367 /** 368 * @brief Reads the Target property and stores in _tachTarget. 369 * Also calls Fan::tachChanged(). 370 * 371 * @param[in] msg - the dbus message 372 */ 373 void handleTargetChange(sdbusplus::message::message& msg); 374 375 /** 376 * @brief Reads the Value property and stores in _tachInput. 377 * Also calls Fan::tachChanged(). 378 * 379 * @param[in] msg - the dbus message 380 */ 381 void handleTachChange(sdbusplus::message::message& msg); 382 383 /** 384 * @brief Updates the Functional property in the inventory 385 * for this tach sensor based on the value passed in. 386 * 387 * @param[in] functional - If the Functional property should 388 * be set to true or false. 389 */ 390 void updateInventory(bool functional); 391 392 /** 393 * @brief the dbus object 394 */ 395 sdbusplus::bus::bus& _bus; 396 397 /** 398 * @brief Reference to the parent Fan object 399 */ 400 Fan& _fan; 401 402 /** 403 * @brief The name of the sensor, including the full path 404 * 405 * For example /xyz/openbmc_project/sensors/fan_tach/fan0 406 */ 407 const std::string _name; 408 409 /** 410 * @brief The inventory name of the sensor, including the full path 411 */ 412 const std::string _invName; 413 414 /** 415 * @brief If functional (not too slow). The parent 416 * fan object sets this. 417 */ 418 bool _functional; 419 420 /** 421 * @brief If the sensor has a Target property (can set speed) 422 */ 423 const bool _hasTarget; 424 425 /** 426 * @brief If the sensor has a D-Bus owner 427 */ 428 bool _hasOwner = true; 429 430 /** 431 * @brief Amount of time to delay updating to functional 432 */ 433 const size_t _funcDelay; 434 435 /** 436 * @brief The interface that the target implements 437 */ 438 const std::string _interface; 439 440 /** 441 * @brief The factor of target to get fan rpm 442 */ 443 const double _factor; 444 445 /** 446 * @brief The offset of target to get fan rpm 447 */ 448 const int64_t _offset; 449 450 /** 451 * @brief The method of out of range 452 */ 453 const size_t _method; 454 455 /** 456 * @brief The threshold for count method 457 */ 458 const size_t _threshold; 459 460 /** 461 * @brief The counter for count method 462 */ 463 size_t _counter = 0; 464 465 /** 466 * @brief The input speed, from the Value dbus property 467 */ 468 double _tachInput = 0; 469 470 /** 471 * @brief The current target speed, from the Target dbus property 472 * (if applicable) 473 */ 474 uint64_t _tachTarget = 0; 475 476 /** 477 * @brief The timeout value to use 478 */ 479 const size_t _timeout; 480 481 /** 482 * @brief Mode that current timer is in 483 */ 484 TimerMode _timerMode; 485 486 /** 487 * The timer object 488 */ 489 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 490 491 /** 492 * @brief The match object for the Value properties changed signal 493 */ 494 std::unique_ptr<sdbusplus::server::match::match> tachSignal; 495 496 /** 497 * @brief The match object for the Target properties changed signal 498 */ 499 std::unique_ptr<sdbusplus::server::match::match> targetSignal; 500 501 /** 502 * @brief The number of seconds to wait between a sensor being set 503 * to nonfunctional and creating an error for it. 504 * 505 * If std::nullopt, no errors will be created. 506 */ 507 const std::optional<size_t> _errorDelay; 508 509 /** 510 * @brief The timer that uses _errorDelay. When it expires an error 511 * will be created for a faulted fan sensor (rotor). 512 * 513 * If _errorDelay is std::nullopt, then this won't be created. 514 */ 515 std::unique_ptr< 516 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 517 _errorTimer; 518 519 /** 520 * @brief The interval, in seconds, to use for the timer that runs 521 * the checks when using the 'count' method. 522 */ 523 size_t _countInterval; 524 525 /** 526 * @brief The timer used by the 'count' method for determining 527 * functional status. 528 */ 529 std::unique_ptr< 530 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 531 _countTimer; 532 }; 533 534 } // namespace monitor 535 } // namespace fan 536 } // namespace phosphor 537