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 auto satisfied = _cause->satisfied(fanHealth); 80 81 // Only start an action if it matches on the current state, 82 // but be able to stop it no matter what the state is. 83 if (!_active && satisfied && (state == _validState)) 84 { 85 // Start the action 86 getLogger().log( 87 std::format("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(std::format("Stopped shutdown action '{}'", 99 _action->name())); 100 _active = false; 101 } 102 else 103 { 104 getLogger().log(std::format( 105 "Could not stop shutdown action '{}'", _action->name())); 106 } 107 } 108 } 109 110 /** 111 * @brief Says if there is an active power off in progress due to 112 * this rule. 113 * 114 * @return bool - If the rule is active or not 115 */ 116 bool active() const 117 { 118 return _active; 119 } 120 121 private: 122 /** 123 * @brief The state the rule is valid for. 124 */ 125 PowerRuleState _validState; 126 127 /** 128 * @brief If there is an active power off in progress. 129 */ 130 bool _active{false}; 131 132 /** 133 * @brief Base class pointer to the power off cause class 134 */ 135 std::unique_ptr<PowerOffCause> _cause; 136 137 /** 138 * @brief Base class pointer to the power off action class 139 */ 140 std::unique_ptr<PowerOffAction> _action; 141 }; 142 143 } // namespace phosphor::fan::monitor 144