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 the factor of the sensor target 174 */ 175 inline double getFactor() const 176 { 177 return _factor; 178 } 179 180 /** 181 * @brief Returns the offset of the sensor target 182 */ 183 inline int64_t getOffset() const 184 { 185 return _offset; 186 } 187 188 /** 189 * @brief Returns the method of out of range 190 */ 191 inline size_t getMethod() const 192 { 193 return _method; 194 } 195 196 /** 197 * @brief Returns the threshold of count method 198 */ 199 inline size_t getThreshold() const 200 { 201 return _threshold; 202 } 203 204 /** 205 * Set the sensor faulted counter 206 */ 207 void setCounter(bool count); 208 209 /** 210 * @brief Returns the sensor faulted count 211 */ 212 inline size_t getCounter() const 213 { 214 return _counter; 215 } 216 217 /** 218 * Returns true if the hardware behind this 219 * sensor is considered working OK/functional. 220 */ 221 inline bool functional() const 222 { 223 return _functional; 224 } 225 226 /** 227 * Set the functional status and update inventory to match 228 */ 229 void setFunctional(bool functional); 230 231 /** 232 * @brief Says if the timer is running or not 233 * 234 * @return bool - if timer is currently running 235 */ 236 inline bool timerRunning() 237 { 238 return _timer.isEnabled(); 239 } 240 241 /** 242 * @brief Stops the timer when the given mode differs and starts 243 * the associated timer for the mode given if not already running 244 * 245 * @param[in] mode - mode of timer to start 246 */ 247 void startTimer(TimerMode mode); 248 249 /** 250 * @brief Stops the timer 251 */ 252 inline void stopTimer() 253 { 254 phosphor::logging::log<phosphor::logging::level::DEBUG>( 255 fmt::format("Stop running timer on tach sensor {}.", _name) 256 .c_str()); 257 _timer.setEnabled(false); 258 } 259 260 /** 261 * @brief Says if the count timer is running 262 * 263 * @return bool - If count timer running 264 */ 265 inline bool countTimerRunning() const 266 { 267 return _countTimer && _countTimer->isEnabled(); 268 } 269 270 /** 271 * @brief Stops the count timer 272 */ 273 void stopCountTimer(); 274 275 /** 276 * @brief Starts the count timer 277 */ 278 void startCountTimer(); 279 280 /** 281 * @brief Return the given timer mode's delay time 282 * 283 * @param[in] mode - mode of timer to get delay time for 284 */ 285 std::chrono::microseconds getDelay(TimerMode mode); 286 287 /** 288 * Returns the sensor name 289 */ 290 inline const std::string& name() const 291 { 292 return _name; 293 }; 294 295 /** 296 * @brief Says if the error timer is running 297 * 298 * @return bool - If the timer is running 299 */ 300 bool errorTimerRunning() const 301 { 302 if (_errorTimer && _errorTimer->isEnabled()) 303 { 304 return true; 305 } 306 return false; 307 } 308 309 /** 310 * @brief Get the current allowed range of speeds 311 * 312 * @param[in] deviation - The configured deviation(in percent) allowed 313 * 314 * @return pair - Min/Max range of speeds allowed 315 */ 316 std::pair<uint64_t, uint64_t> getRange(const size_t deviation) const; 317 318 /** 319 * @brief Processes the current state of the sensor 320 */ 321 void processState(); 322 323 /** 324 * @brief Resets the monitoring method of the sensor 325 */ 326 void resetMethod(); 327 328 /** 329 * @brief Refreshes the tach input and target values by 330 * reading them from D-Bus. 331 */ 332 void updateTachAndTarget(); 333 334 private: 335 /** 336 * @brief Returns the match string to use for matching 337 * on a properties changed signal. 338 */ 339 std::string getMatchString(const std::string& interface); 340 341 /** 342 * @brief Reads the Target property and stores in _tachTarget. 343 * Also calls Fan::tachChanged(). 344 * 345 * @param[in] msg - the dbus message 346 */ 347 void handleTargetChange(sdbusplus::message::message& msg); 348 349 /** 350 * @brief Reads the Value property and stores in _tachInput. 351 * Also calls Fan::tachChanged(). 352 * 353 * @param[in] msg - the dbus message 354 */ 355 void handleTachChange(sdbusplus::message::message& msg); 356 357 /** 358 * @brief Updates the Functional property in the inventory 359 * for this tach sensor based on the value passed in. 360 * 361 * @param[in] functional - If the Functional property should 362 * be set to true or false. 363 */ 364 void updateInventory(bool functional); 365 366 /** 367 * @brief the dbus object 368 */ 369 sdbusplus::bus::bus& _bus; 370 371 /** 372 * @brief Reference to the parent Fan object 373 */ 374 Fan& _fan; 375 376 /** 377 * @brief The name of the sensor, including the full path 378 * 379 * For example /xyz/openbmc_project/sensors/fan_tach/fan0 380 */ 381 const std::string _name; 382 383 /** 384 * @brief The inventory name of the sensor, including the full path 385 */ 386 const std::string _invName; 387 388 /** 389 * @brief If functional (not too slow). The parent 390 * fan object sets this. 391 */ 392 bool _functional; 393 394 /** 395 * @brief If the sensor has a Target property (can set speed) 396 */ 397 const bool _hasTarget; 398 399 /** 400 * @brief Amount of time to delay updating to functional 401 */ 402 const size_t _funcDelay; 403 404 /** 405 * @brief The interface that the target implements 406 */ 407 const std::string _interface; 408 409 /** 410 * @brief The factor of target to get fan rpm 411 */ 412 const double _factor; 413 414 /** 415 * @brief The offset of target to get fan rpm 416 */ 417 const int64_t _offset; 418 419 /** 420 * @brief The method of out of range 421 */ 422 const size_t _method; 423 424 /** 425 * @brief The threshold for count method 426 */ 427 const size_t _threshold; 428 429 /** 430 * @brief The counter for count method 431 */ 432 size_t _counter = 0; 433 434 /** 435 * @brief The input speed, from the Value dbus property 436 */ 437 double _tachInput = 0; 438 439 /** 440 * @brief The current target speed, from the Target dbus property 441 * (if applicable) 442 */ 443 uint64_t _tachTarget = 0; 444 445 /** 446 * @brief The timeout value to use 447 */ 448 const size_t _timeout; 449 450 /** 451 * @brief Mode that current timer is in 452 */ 453 TimerMode _timerMode; 454 455 /** 456 * The timer object 457 */ 458 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 459 460 /** 461 * @brief The match object for the Value properties changed signal 462 */ 463 std::unique_ptr<sdbusplus::server::match::match> tachSignal; 464 465 /** 466 * @brief The match object for the Target properties changed signal 467 */ 468 std::unique_ptr<sdbusplus::server::match::match> targetSignal; 469 470 /** 471 * @brief The number of seconds to wait between a sensor being set 472 * to nonfunctional and creating an error for it. 473 * 474 * If std::nullopt, no errors will be created. 475 */ 476 const std::optional<size_t> _errorDelay; 477 478 /** 479 * @brief The timer that uses _errorDelay. When it expires an error 480 * will be created for a faulted fan sensor (rotor). 481 * 482 * If _errorDelay is std::nullopt, then this won't be created. 483 */ 484 std::unique_ptr< 485 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 486 _errorTimer; 487 488 /** 489 * @brief The interval, in seconds, to use for the timer that runs 490 * the checks when using the 'count' method. 491 */ 492 size_t _countInterval; 493 494 /** 495 * @brief The timer used by the 'count' method for determining 496 * functional status. 497 */ 498 std::unique_ptr< 499 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 500 _countTimer; 501 }; 502 503 } // namespace monitor 504 } // namespace fan 505 } // namespace phosphor 506