#pragma once #include "logging.hpp" #include "power_off_action.hpp" #include "power_off_cause.hpp" #include namespace phosphor::fan::monitor { /** * @brief Describes when the rule should be checked. * either right at PGOOD, or anytime at runtime. */ enum class PowerRuleState { atPgood, // Only at the moment when PGOOD switches on. runtime // Anytime that power is on. }; /** * @class PowerOffRule * * This class implements a power off rule, which has a cause * that is based on fan status, and an action which is the type of * power off that will occur when the cause is satisfied. * * The user of this class calls the 'check()' method when fan * status may have changed, and then the power off action may * be started. */ class PowerOffRule { public: PowerOffRule() = delete; ~PowerOffRule() = default; PowerOffRule(const PowerOffRule&) = delete; PowerOffRule& operator=(const PowerOffRule&) = delete; PowerOffRule(PowerOffRule&&) = delete; PowerOffRule& operator=(PowerOffRule&&) = delete; /** * @brief Constructor * * @param[in] validState - What state the rule is valid for * @param[in] cause - The power off cause to use * @param[in] action - The power off action to use */ PowerOffRule(PowerRuleState validState, std::unique_ptr cause, std::unique_ptr action) : _validState(validState), _cause(std::move(cause)), _action(std::move(action)) {} /** * @brief Used to cancel a delay based power off when * there is still time left. */ void cancel() { _active = false; // force the cancel _action->cancel(true); } /** * @brief Checks the cause against the passed in fan health * and starts the power off action if the cause * is satisfied. * * @param[in] state - The state to check the rule at * @param[in] fanHealth - The fan health map */ void check(PowerRuleState state, const FanHealth& fanHealth) { auto satisfied = _cause->satisfied(fanHealth); // Only start an action if it matches on the current state, // but be able to stop it no matter what the state is. if (!_active && satisfied && (state == _validState)) { // Start the action getLogger().log( std::format("Starting shutdown action '{}' due to cause '{}'", _action->name(), _cause->name())); _active = true; _action->start(); } else if (_active && !satisfied) { // Attempt to cancel the action, but don't force it if (_action->cancel(false)) { getLogger().log(std::format("Stopped shutdown action '{}'", _action->name())); _active = false; } else { getLogger().log(std::format( "Could not stop shutdown action '{}'", _action->name())); } } } /** * @brief Says if there is an active power off in progress due to * this rule. * * @return bool - If the rule is active or not */ bool active() const { return _active; } private: /** * @brief The state the rule is valid for. */ PowerRuleState _validState; /** * @brief If there is an active power off in progress. */ bool _active{false}; /** * @brief Base class pointer to the power off cause class */ std::unique_ptr _cause; /** * @brief Base class pointer to the power off action class */ std::unique_ptr _action; }; } // namespace phosphor::fan::monitor