blob: 05d4ff65b64387325f92a9c8941abf60503e864f [file] [log] [blame]
Matt Spinler69b0cf02020-10-14 10:59:03 -05001#pragma once
2
3#include "logging.hpp"
4#include "power_interface.hpp"
5
6#include <fmt/format.h>
7
8#include <sdeventplus/clock.hpp>
9#include <sdeventplus/event.hpp>
10#include <sdeventplus/utility/timer.hpp>
11
12#include <chrono>
13
14namespace phosphor::fan::monitor
15{
16
17/**
18 * @class PowerOffAction
19 *
20 * This is the base class for a power off action, which is
21 * used by the PowerOffRule class to do different types of
22 * power offs based on fan failures.
23 *
24 * The power off is started with the start() method, and the
25 * derived class may or may not allow it to be stopped with
26 * the cancel() method, which is really only useful when
27 * there is a delay before the power off.
28 *
29 * It uses the PowerInterfaceBase object pointer to perform
30 * the D-Bus call to do the power off, so it can be mocked
31 * for testing.
32 */
33class PowerOffAction
34{
35 public:
36 PowerOffAction() = delete;
37 virtual ~PowerOffAction() = default;
38 PowerOffAction(const PowerOffAction&) = delete;
39 PowerOffAction& operator=(const PowerOffAction&) = delete;
40 PowerOffAction(PowerOffAction&&) = delete;
41 PowerOffAction& operator=(PowerOffAction&&) = delete;
42
43 /**
44 * @brief Constructor
45 *
46 * @param[in] name - The action name. Used for tracing.
47 * powerInterface - The object used to invoke the power off.
48 */
49 PowerOffAction(const std::string& name,
50 std::shared_ptr<PowerInterfaceBase> powerInterface) :
51 _name(name),
52 _powerIface(std::move(powerInterface)),
53 _event(sdeventplus::Event::get_default())
54 {}
55
56 /**
57 * @brief Starts the power off.
58 *
59 * Though this occurs in the child class, usually this
60 * involves starting a timer and then powering off when it
61 * times out.
62 */
63 virtual void start() = 0;
64
65 /**
66 * @brief Attempts to cancel the power off, if the derived
67 * class allows it, and assuming the power off hasn't
68 * already happened.
69 *
70 * The 'force' parameter is mainly for use when something else
71 * powered off the system so this action doesn't need to run
72 * anymore even if it isn't usually cancelable.
73 *
74 * @param[in] force - If the cancel should be forced
75 *
76 * @return bool - If the cancel was allowed/successful
77 */
78 virtual bool cancel(bool force) = 0;
79
80 /**
81 * @brief If the power off action is currently in progress, which
82 * usually means it's still in the delay time before the
83 * power off D-Bus command is executed.
84 *
85 * @return bool - If the action is active
86 */
87 bool active() const
88 {
89 return _active;
90 }
91
92 /**
93 * @brief Returns the name of the action
94 *
95 * @return const std::string& - The name
96 */
97 const std::string& name() const
98 {
99 return _name;
100 }
101
102 protected:
103 /**
104 * @brief The name of the action, which is set by the
105 * derived class.
106 */
107 const std::string _name;
108
109 /**
110 * @brief If the action is currently active or not.
111 */
112 bool _active = false;
113
114 /**
115 * @brief The object used to invoke the power off with.
116 */
117 std::shared_ptr<PowerInterfaceBase> _powerIface;
118
119 /**
120 * @brief The event loop object. Needed by timers.
121 */
122 sdeventplus::Event _event;
123};
124
125/**
126 * @class HardPowerOff
127 *
128 * This class is derived from the PowerOffAction class
129 * and will execute a hard power off after some delay.
130 */
131class HardPowerOff : public PowerOffAction
132{
133 public:
134 HardPowerOff() = delete;
135 ~HardPowerOff() = default;
136 HardPowerOff(const HardPowerOff&) = delete;
137 HardPowerOff& operator=(const HardPowerOff&) = delete;
138 HardPowerOff(HardPowerOff&&) = delete;
139 HardPowerOff& operator=(HardPowerOff&&) = delete;
140
141 /**
142 * @brief Constructor
143 *
144 * @param[in] delay - The amount of time in seconds to wait before
145 * doing the power off
146 * @param[in] powerInterface - The object to use to do the power off
147 */
148 HardPowerOff(uint32_t delay,
149 std::shared_ptr<PowerInterfaceBase> powerInterface) :
150 PowerOffAction("Hard Power Off: " + std::to_string(delay) + "s",
151 powerInterface),
152 _delay(delay),
153 _timer(_event, std::bind(std::mem_fn(&HardPowerOff::powerOff), this))
154 {}
155
156 /**
157 * @brief Starts a timer upon the expiration of which the
158 * hard power off will be done.
159 */
160 void start() override
161 {
162 _timer.restartOnce(_delay);
163 }
164
165 /**
166 * @brief Cancels the timer. This is always allowed.
167 *
168 * @param[in] force - If the cancel should be forced or not
169 * (not checked in this case)
170 * @return bool - Always returns true
171 */
172 bool cancel(bool) override
173 {
174 if (_timer.isEnabled())
175 {
176 _timer.setEnabled(false);
177 }
178
179 // Can always be canceled
180 return true;
181 }
182
183 /**
184 * @brief Performs the hard power off.
185 */
186 void powerOff()
187 {
188 getLogger().log(
189 fmt::format("Action '{}' executing hard power off", name()));
190 _powerIface->hardPowerOff();
191 }
192
193 private:
194 /**
195 * @brief The number of seconds to wait between starting the
196 * action and doing the power off.
197 */
198 std::chrono::seconds _delay;
199
200 /**
201 * @brief The Timer object used to handle the delay.
202 */
203 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
204};
205
206/**
207 * @class SoftPowerOff
208 *
209 * This class is derived from the PowerOffAction class
210 * and will execute a soft power off after some delay.
211 */
212class SoftPowerOff : public PowerOffAction
213{
214 public:
215 SoftPowerOff() = delete;
216 ~SoftPowerOff() = default;
217 SoftPowerOff(const SoftPowerOff&) = delete;
218 SoftPowerOff& operator=(const SoftPowerOff&) = delete;
219 SoftPowerOff(SoftPowerOff&&) = delete;
220 SoftPowerOff& operator=(SoftPowerOff&&) = delete;
221
222 /**
223 * @brief Constructor
224 *
225 * @param[in] delay - The amount of time in seconds to wait before
226 * doing the power off
227 * @param[in] powerInterface - The object to use to do the power off
228 */
229 SoftPowerOff(uint32_t delay,
230 std::shared_ptr<PowerInterfaceBase> powerInterface) :
231 PowerOffAction("Soft Power Off: " + std::to_string(delay) + "s",
232 powerInterface),
233 _delay(delay),
234 _timer(_event, std::bind(std::mem_fn(&SoftPowerOff::powerOff), this))
235 {}
236
237 /**
238 * @brief Starts a timer upon the expiration of which the
239 * soft power off will be done.
240 */
241 void start() override
242 {
243 _timer.restartOnce(_delay);
244 }
245
246 /**
247 * @brief Cancels the timer. This is always allowed.
248 *
249 * @param[in] force - If the cancel should be forced or not
250 * (not checked in this case)
251 * @return bool - Always returns true
252 */
253 bool cancel(bool) override
254 {
255 if (_timer.isEnabled())
256 {
257 _timer.setEnabled(false);
258 }
259
260 // Can always be canceled
261 return true;
262 }
263
264 /**
265 * @brief Performs the soft power off.
266 */
267 void powerOff()
268 {
269 getLogger().log(
270 fmt::format("Action '{}' executing soft power off", name()));
271 _powerIface->softPowerOff();
272 }
273
274 private:
275 /**
276 * @brief The number of seconds to wait between starting the
277 * action and doing the power off.
278 */
279 std::chrono::seconds _delay;
280
281 /**
282 * @brief The Timer object used to handle the delay.
283 */
284 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
285};
286
287/**
288 * @class EpowPowerOff
289 *
290 * Still TODO, but has a cancelable service mode delay followed
291 * by an uncancelable meltdown delay followed by a hard power off, with
292 * some sort of EPOW alert in there as well.
293 */
294class EpowPowerOff : public PowerOffAction
295{
296 public:
297 EpowPowerOff() = delete;
298 ~EpowPowerOff() = default;
299 EpowPowerOff(const EpowPowerOff&) = delete;
300 EpowPowerOff& operator=(const EpowPowerOff&) = delete;
301 EpowPowerOff(EpowPowerOff&&) = delete;
302 EpowPowerOff& operator=(EpowPowerOff&&) = delete;
303
304 EpowPowerOff(uint32_t serviceModeDelay, uint32_t meltdownDelay,
305 std::shared_ptr<PowerInterfaceBase> powerInterface) :
306 PowerOffAction("EPOW Power Off: " + std::to_string(serviceModeDelay) +
307 "s/" + std::to_string(meltdownDelay) + "s",
308 powerInterface),
309 _serviceModeDelay(serviceModeDelay), _meltdownDelay(meltdownDelay)
310 {}
311
312 void start() override
313 {
314 // TODO
315 }
316
317 bool cancel(bool) override
318 {
319 // TODO
320 return true;
321 }
322
323 private:
324 std::chrono::seconds _serviceModeDelay;
325 std::chrono::seconds _meltdownDelay;
326};
327} // namespace phosphor::fan::monitor