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