1 #pragma once 2 3 #include "logging.hpp" 4 #include "power_off_action.hpp" 5 #include "power_off_cause.hpp" 6 7 #include <memory> 8 9 namespace phosphor::fan::monitor 10 { 11 12 /** 13 * @brief Describes when the rule should be checked. 14 * either right at PGOOD, or anytime at runtime. 15 */ 16 enum class PowerRuleState 17 { 18 atPgood, // Only at the moment when PGOOD switches on. 19 runtime // Anytime that power is on. 20 }; 21 22 /** 23 * @class PowerOffRule 24 * 25 * This class implements a power off rule, which has a cause 26 * that is based on fan status, and an action which is the type of 27 * power off that will occur when the cause is satisfied. 28 * 29 * The user of this class calls the 'check()' method when fan 30 * status may have changed, and then the power off action may 31 * be started. 32 */ 33 class PowerOffRule 34 { 35 public: 36 PowerOffRule() = delete; 37 ~PowerOffRule() = default; 38 PowerOffRule(const PowerOffRule&) = delete; 39 PowerOffRule& operator=(const PowerOffRule&) = delete; 40 PowerOffRule(PowerOffRule&&) = delete; 41 PowerOffRule& operator=(PowerOffRule&&) = delete; 42 43 /** 44 * @brief Constructor 45 * 46 * @param[in] validState - What state the rule is valid for 47 * @param[in] cause - The power off cause to use 48 * @param[in] action - The power off action to use 49 */ 50 PowerOffRule(PowerRuleState validState, 51 std::unique_ptr<PowerOffCause> cause, 52 std::unique_ptr<PowerOffAction> action) : 53 _validState(validState), 54 _cause(std::move(cause)), _action(std::move(action)) 55 {} 56 57 /** 58 * @brief Used to cancel a delay based power off when 59 * there is still time left. 60 */ 61 void cancel() 62 { 63 _active = false; 64 65 // force the cancel 66 _action->cancel(true); 67 } 68 69 /** 70 * @brief Checks the cause against the passed in fan health 71 * and starts the power off action if the cause 72 * is satisfied. 73 * 74 * @param[in] state - The state to check the rule at 75 * @param[in] fanHealth - The fan health map 76 */ 77 void check(PowerRuleState state, const FanHealth& fanHealth) 78 { 79 if (state == _validState) 80 { 81 auto satisfied = _cause->satisfied(fanHealth); 82 83 if (!_active && satisfied) 84 { 85 // Start the action 86 _active = true; 87 _action->start(); 88 getLogger().log(fmt::format( 89 "Starting shutdown action '{}' due to cause '{}'", 90 _action->name(), _cause->name())); 91 } 92 else if (_active && !satisfied) 93 { 94 // Attempt to cancel the action, but don't force it 95 if (_action->cancel(false)) 96 { 97 getLogger().log(fmt::format("Stopped shutdown action '{}'", 98 _action->name())); 99 _active = false; 100 } 101 else 102 { 103 getLogger().log( 104 fmt::format("Could not stop shutdown action '{}'", 105 _action->name())); 106 } 107 } 108 } 109 } 110 111 /** 112 * @brief Says if there is an active power off in progress due to 113 * this rule. 114 * 115 * @return bool - If the rule is active or not 116 */ 117 bool active() const 118 { 119 return _active; 120 } 121 122 private: 123 /** 124 * @brief The state the rule is valid for. 125 */ 126 PowerRuleState _validState; 127 128 /** 129 * @brief If there is an active power off in progress. 130 */ 131 bool _active{false}; 132 133 /** 134 * @brief Base class pointer to the power off cause class 135 */ 136 std::unique_ptr<PowerOffCause> _cause; 137 138 /** 139 * @brief Base class pointer to the power off action class 140 */ 141 std::unique_ptr<PowerOffAction> _action; 142 }; 143 144 } // namespace phosphor::fan::monitor 145