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 * 102 * @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, 107 size_t method, size_t threshold, size_t timeout, 108 const std::optional<size_t>& errorDelay, 109 const sdeventplus::Event& event); 110 111 /** 112 * @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 /** 143 * @brief Returns the target speed value 144 */ 145 uint64_t getTarget() const; 146 147 /** 148 * @brief Returns the input speed value 149 */ 150 inline double getInput() const 151 { 152 return _tachInput; 153 } 154 155 /** 156 * @brief Returns true if sensor has a target 157 */ 158 inline bool hasTarget() const 159 { 160 return _hasTarget; 161 } 162 163 /** 164 * @brief Returns the interface of the sensor target 165 */ 166 inline std::string getInterface() const 167 { 168 return _interface; 169 } 170 171 /** 172 * @brief Returns the factor of the sensor target 173 */ 174 inline double getFactor() const 175 { 176 return _factor; 177 } 178 179 /** 180 * @brief Returns the offset of the sensor target 181 */ 182 inline int64_t getOffset() const 183 { 184 return _offset; 185 } 186 187 /** 188 * @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 /** 217 * 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 } 224 225 /** 226 * Set the functional status and update inventory to match 227 */ 228 void setFunctional(bool functional); 229 230 /** 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 } 239 240 /** 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); 247 248 /** 249 * @brief Stops the timer 250 */ 251 inline void stopTimer() 252 { 253 phosphor::logging::log<phosphor::logging::level::DEBUG>( 254 fmt::format("Stop running timer on tach sensor {}.", _name) 255 .c_str()); 256 _timer.setEnabled(false); 257 } 258 259 /** 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); 265 266 /** 267 * Returns the sensor name 268 */ 269 inline const std::string& name() const 270 { 271 return _name; 272 }; 273 274 /** 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 288 /** 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 297 /** 298 * @brief Processes the current state of the sensor 299 */ 300 void processState(); 301 302 /** 303 * @brief Resets the monitoring method of the sensor 304 */ 305 void resetMethod(); 306 307 /** 308 * @brief Refreshes the tach input and target values by 309 * reading them from D-Bus. 310 */ 311 void updateTachAndTarget(); 312 313 private: 314 /** 315 * @brief Returns the match string to use for matching 316 * on a properties changed signal. 317 */ 318 std::string getMatchString(const std::string& interface); 319 320 /** 321 * @brief Reads the Target property and stores in _tachTarget. 322 * Also calls Fan::tachChanged(). 323 * 324 * @param[in] msg - the dbus message 325 */ 326 void handleTargetChange(sdbusplus::message::message& msg); 327 328 /** 329 * @brief Reads the Value property and stores in _tachInput. 330 * Also calls Fan::tachChanged(). 331 * 332 * @param[in] msg - the dbus message 333 */ 334 void handleTachChange(sdbusplus::message::message& msg); 335 336 /** 337 * @brief Updates the Functional property in the inventory 338 * for this tach sensor based on the value passed in. 339 * 340 * @param[in] functional - If the Functional property should 341 * be set to true or false. 342 */ 343 void updateInventory(bool functional); 344 345 /** 346 * @brief the dbus object 347 */ 348 sdbusplus::bus::bus& _bus; 349 350 /** 351 * @brief Reference to the parent Fan object 352 */ 353 Fan& _fan; 354 355 /** 356 * @brief The name of the sensor, including the full path 357 * 358 * For example /xyz/openbmc_project/sensors/fan_tach/fan0 359 */ 360 const std::string _name; 361 362 /** 363 * @brief The inventory name of the sensor, including the full path 364 */ 365 const std::string _invName; 366 367 /** 368 * @brief If functional (not too slow). The parent 369 * fan object sets this. 370 */ 371 bool _functional; 372 373 /** 374 * @brief If the sensor has a Target property (can set speed) 375 */ 376 const bool _hasTarget; 377 378 /** 379 * @brief Amount of time to delay updating to functional 380 */ 381 const size_t _funcDelay; 382 383 /** 384 * @brief The interface that the target implements 385 */ 386 const std::string _interface; 387 388 /** 389 * @brief The factor of target to get fan rpm 390 */ 391 const double _factor; 392 393 /** 394 * @brief The offset of target to get fan rpm 395 */ 396 const int64_t _offset; 397 398 /** 399 * @brief The method of out of range 400 */ 401 const size_t _method; 402 403 /** 404 * @brief The threshold for count method 405 */ 406 const size_t _threshold; 407 408 /** 409 * @brief The counter for count method 410 */ 411 size_t _counter = 0; 412 413 /** 414 * @brief The input speed, from the Value dbus property 415 */ 416 double _tachInput = 0; 417 418 /** 419 * @brief The current target speed, from the Target dbus property 420 * (if applicable) 421 */ 422 uint64_t _tachTarget = 0; 423 424 /** 425 * @brief The timeout value to use 426 */ 427 const size_t _timeout; 428 429 /** 430 * @brief Mode that current timer is in 431 */ 432 TimerMode _timerMode; 433 434 /** 435 * The timer object 436 */ 437 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 438 439 /** 440 * @brief The match object for the Value properties changed signal 441 */ 442 std::unique_ptr<sdbusplus::server::match::match> tachSignal; 443 444 /** 445 * @brief The match object for the Target properties changed signal 446 */ 447 std::unique_ptr<sdbusplus::server::match::match> targetSignal; 448 449 /** 450 * @brief The number of seconds to wait between a sensor being set 451 * to nonfunctional and creating an error for it. 452 * 453 * If std::nullopt, no errors will be created. 454 */ 455 const std::optional<size_t> _errorDelay; 456 457 /** 458 * @brief The timer that uses _errorDelay. When it expires an error 459 * will be created for a faulted fan sensor (rotor). 460 * 461 * If _errorDelay is std::nullopt, then this won't be created. 462 */ 463 std::unique_ptr< 464 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 465 _errorTimer; 466 }; 467 468 } // namespace monitor 469 } // namespace fan 470 } // namespace phosphor 471