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                 fmt::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(fmt::format("Stopped shutdown action '{}'",
99                                             _action->name()));
100                 _active = false;
101             }
102             else
103             {
104                 getLogger().log(fmt::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