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 getLogger().log(fmt::format( 87 "Starting shutdown action '{}' due to cause '{}'", 88 _action->name(), _cause->name())); 89 90 _active = true; 91 _action->start(); 92 } 93 else if (_active && !satisfied) 94 { 95 // Attempt to cancel the action, but don't force it 96 if (_action->cancel(false)) 97 { 98 getLogger().log(fmt::format("Stopped shutdown action '{}'", 99 _action->name())); 100 _active = false; 101 } 102 else 103 { 104 getLogger().log( 105 fmt::format("Could not stop shutdown action '{}'", 106 _action->name())); 107 } 108 } 109 } 110 } 111 112 /** 113 * @brief Says if there is an active power off in progress due to 114 * this rule. 115 * 116 * @return bool - If the rule is active or not 117 */ 118 bool active() const 119 { 120 return _active; 121 } 122 123 private: 124 /** 125 * @brief The state the rule is valid for. 126 */ 127 PowerRuleState _validState; 128 129 /** 130 * @brief If there is an active power off in progress. 131 */ 132 bool _active{false}; 133 134 /** 135 * @brief Base class pointer to the power off cause class 136 */ 137 std::unique_ptr<PowerOffCause> _cause; 138 139 /** 140 * @brief Base class pointer to the power off action class 141 */ 142 std::unique_ptr<PowerOffAction> _action; 143 }; 144 145 } // namespace phosphor::fan::monitor 146