blob: 59b1406f3a10fa03fc1d1064e0d802e651f40dce [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:
Matt Spinlerac1efc12020-10-27 10:20:11 -050036 using PrePowerOffFunc = std::function<void()>;
37
Matt Spinler69b0cf02020-10-14 10:59:03 -050038 PowerOffAction() = delete;
39 virtual ~PowerOffAction() = default;
40 PowerOffAction(const PowerOffAction&) = delete;
41 PowerOffAction& operator=(const PowerOffAction&) = delete;
42 PowerOffAction(PowerOffAction&&) = delete;
43 PowerOffAction& operator=(PowerOffAction&&) = delete;
44
45 /**
46 * @brief Constructor
47 *
48 * @param[in] name - The action name. Used for tracing.
Matt Spinlerac1efc12020-10-27 10:20:11 -050049 * @param[in] powerInterface - The object used to invoke the power off.
50 * @param[in] powerOffFunc - A function to call right before the power
51 * off occurs (after any delays). May be
52 * empty if no function is necessary.
Matt Spinler69b0cf02020-10-14 10:59:03 -050053 */
54 PowerOffAction(const std::string& name,
Matt Spinlerac1efc12020-10-27 10:20:11 -050055 std::shared_ptr<PowerInterfaceBase> powerInterface,
56 PrePowerOffFunc& powerOffFunc) :
Matt Spinler69b0cf02020-10-14 10:59:03 -050057 _name(name),
58 _powerIface(std::move(powerInterface)),
Matt Spinlerac1efc12020-10-27 10:20:11 -050059 _event(sdeventplus::Event::get_default()),
60 _prePowerOffFunc(powerOffFunc)
Matt Spinler69b0cf02020-10-14 10:59:03 -050061 {}
62
63 /**
64 * @brief Starts the power off.
65 *
66 * Though this occurs in the child class, usually this
67 * involves starting a timer and then powering off when it
68 * times out.
69 */
70 virtual void start() = 0;
71
72 /**
73 * @brief Attempts to cancel the power off, if the derived
74 * class allows it, and assuming the power off hasn't
75 * already happened.
76 *
77 * The 'force' parameter is mainly for use when something else
78 * powered off the system so this action doesn't need to run
79 * anymore even if it isn't usually cancelable.
80 *
81 * @param[in] force - If the cancel should be forced
82 *
83 * @return bool - If the cancel was allowed/successful
84 */
85 virtual bool cancel(bool force) = 0;
86
87 /**
88 * @brief If the power off action is currently in progress, which
89 * usually means it's still in the delay time before the
90 * power off D-Bus command is executed.
91 *
92 * @return bool - If the action is active
93 */
94 bool active() const
95 {
96 return _active;
97 }
98
99 /**
100 * @brief Returns the name of the action
101 *
102 * @return const std::string& - The name
103 */
104 const std::string& name() const
105 {
106 return _name;
107 }
108
109 protected:
110 /**
111 * @brief The name of the action, which is set by the
112 * derived class.
113 */
114 const std::string _name;
115
116 /**
117 * @brief If the action is currently active or not.
118 */
119 bool _active = false;
120
121 /**
122 * @brief The object used to invoke the power off with.
123 */
124 std::shared_ptr<PowerInterfaceBase> _powerIface;
125
126 /**
127 * @brief The event loop object. Needed by timers.
128 */
129 sdeventplus::Event _event;
Matt Spinlerac1efc12020-10-27 10:20:11 -0500130
131 /**
132 * @brief A function that will be called right before
133 * the power off.
134 */
135 PrePowerOffFunc _prePowerOffFunc;
Matt Spinler69b0cf02020-10-14 10:59:03 -0500136};
137
138/**
139 * @class HardPowerOff
140 *
141 * This class is derived from the PowerOffAction class
142 * and will execute a hard power off after some delay.
143 */
144class HardPowerOff : public PowerOffAction
145{
146 public:
147 HardPowerOff() = delete;
148 ~HardPowerOff() = default;
149 HardPowerOff(const HardPowerOff&) = delete;
150 HardPowerOff& operator=(const HardPowerOff&) = delete;
151 HardPowerOff(HardPowerOff&&) = delete;
152 HardPowerOff& operator=(HardPowerOff&&) = delete;
153
154 /**
155 * @brief Constructor
156 *
157 * @param[in] delay - The amount of time in seconds to wait before
158 * doing the power off
159 * @param[in] powerInterface - The object to use to do the power off
Matt Spinlerac1efc12020-10-27 10:20:11 -0500160 * @param[in] func - A function to call right before the power
161 * off occurs (after the delay). May be
162 * empty if no function is necessary.
Matt Spinler69b0cf02020-10-14 10:59:03 -0500163 */
164 HardPowerOff(uint32_t delay,
Matt Spinlerac1efc12020-10-27 10:20:11 -0500165 std::shared_ptr<PowerInterfaceBase> powerInterface,
166 PrePowerOffFunc func) :
Matt Spinler69b0cf02020-10-14 10:59:03 -0500167 PowerOffAction("Hard Power Off: " + std::to_string(delay) + "s",
Matt Spinlerac1efc12020-10-27 10:20:11 -0500168 powerInterface, func),
Matt Spinler69b0cf02020-10-14 10:59:03 -0500169 _delay(delay),
170 _timer(_event, std::bind(std::mem_fn(&HardPowerOff::powerOff), this))
171 {}
172
173 /**
174 * @brief Starts a timer upon the expiration of which the
175 * hard power off will be done.
176 */
177 void start() override
178 {
179 _timer.restartOnce(_delay);
180 }
181
182 /**
183 * @brief Cancels the timer. This is always allowed.
184 *
185 * @param[in] force - If the cancel should be forced or not
186 * (not checked in this case)
187 * @return bool - Always returns true
188 */
189 bool cancel(bool) override
190 {
191 if (_timer.isEnabled())
192 {
193 _timer.setEnabled(false);
194 }
195
196 // Can always be canceled
197 return true;
198 }
199
200 /**
201 * @brief Performs the hard power off.
202 */
203 void powerOff()
204 {
Matt Spinlerac1efc12020-10-27 10:20:11 -0500205
206 if (_prePowerOffFunc)
207 {
208 _prePowerOffFunc();
209 }
210
Matt Spinler69b0cf02020-10-14 10:59:03 -0500211 getLogger().log(
212 fmt::format("Action '{}' executing hard power off", name()));
213 _powerIface->hardPowerOff();
214 }
215
216 private:
217 /**
218 * @brief The number of seconds to wait between starting the
219 * action and doing the power off.
220 */
221 std::chrono::seconds _delay;
222
223 /**
224 * @brief The Timer object used to handle the delay.
225 */
226 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
227};
228
229/**
230 * @class SoftPowerOff
231 *
232 * This class is derived from the PowerOffAction class
233 * and will execute a soft power off after some delay.
234 */
235class SoftPowerOff : public PowerOffAction
236{
237 public:
238 SoftPowerOff() = delete;
239 ~SoftPowerOff() = default;
240 SoftPowerOff(const SoftPowerOff&) = delete;
241 SoftPowerOff& operator=(const SoftPowerOff&) = delete;
242 SoftPowerOff(SoftPowerOff&&) = delete;
243 SoftPowerOff& operator=(SoftPowerOff&&) = delete;
244
245 /**
246 * @brief Constructor
247 *
248 * @param[in] delay - The amount of time in seconds to wait before
249 * doing the power off
250 * @param[in] powerInterface - The object to use to do the power off
Matt Spinlerac1efc12020-10-27 10:20:11 -0500251 * @param[in] func - A function to call right before the power
252 * off occurs (after the delay). May be
253 * empty if no function is necessary.
Matt Spinler69b0cf02020-10-14 10:59:03 -0500254 */
255 SoftPowerOff(uint32_t delay,
Matt Spinlerac1efc12020-10-27 10:20:11 -0500256 std::shared_ptr<PowerInterfaceBase> powerInterface,
257 PrePowerOffFunc func) :
Matt Spinler69b0cf02020-10-14 10:59:03 -0500258 PowerOffAction("Soft Power Off: " + std::to_string(delay) + "s",
Matt Spinlerac1efc12020-10-27 10:20:11 -0500259 powerInterface, func),
Matt Spinler69b0cf02020-10-14 10:59:03 -0500260 _delay(delay),
261 _timer(_event, std::bind(std::mem_fn(&SoftPowerOff::powerOff), this))
262 {}
263
264 /**
265 * @brief Starts a timer upon the expiration of which the
266 * soft power off will be done.
267 */
268 void start() override
269 {
270 _timer.restartOnce(_delay);
271 }
272
273 /**
274 * @brief Cancels the timer. This is always allowed.
275 *
276 * @param[in] force - If the cancel should be forced or not
277 * (not checked in this case)
278 * @return bool - Always returns true
279 */
280 bool cancel(bool) override
281 {
282 if (_timer.isEnabled())
283 {
284 _timer.setEnabled(false);
285 }
286
287 // Can always be canceled
288 return true;
289 }
290
291 /**
292 * @brief Performs the soft power off.
293 */
294 void powerOff()
295 {
Matt Spinlerac1efc12020-10-27 10:20:11 -0500296 if (_prePowerOffFunc)
297 {
298 _prePowerOffFunc();
299 }
300
Matt Spinler69b0cf02020-10-14 10:59:03 -0500301 getLogger().log(
302 fmt::format("Action '{}' executing soft power off", name()));
303 _powerIface->softPowerOff();
304 }
305
306 private:
307 /**
308 * @brief The number of seconds to wait between starting the
309 * action and doing the power off.
310 */
311 std::chrono::seconds _delay;
312
313 /**
314 * @brief The Timer object used to handle the delay.
315 */
316 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer;
317};
318
319/**
320 * @class EpowPowerOff
321 *
322 * Still TODO, but has a cancelable service mode delay followed
323 * by an uncancelable meltdown delay followed by a hard power off, with
324 * some sort of EPOW alert in there as well.
325 */
326class EpowPowerOff : public PowerOffAction
327{
328 public:
329 EpowPowerOff() = delete;
330 ~EpowPowerOff() = default;
331 EpowPowerOff(const EpowPowerOff&) = delete;
332 EpowPowerOff& operator=(const EpowPowerOff&) = delete;
333 EpowPowerOff(EpowPowerOff&&) = delete;
334 EpowPowerOff& operator=(EpowPowerOff&&) = delete;
335
336 EpowPowerOff(uint32_t serviceModeDelay, uint32_t meltdownDelay,
Matt Spinlerac1efc12020-10-27 10:20:11 -0500337 std::shared_ptr<PowerInterfaceBase> powerInterface,
338 PrePowerOffFunc func) :
Matt Spinler69b0cf02020-10-14 10:59:03 -0500339 PowerOffAction("EPOW Power Off: " + std::to_string(serviceModeDelay) +
340 "s/" + std::to_string(meltdownDelay) + "s",
Matt Spinlerac1efc12020-10-27 10:20:11 -0500341 powerInterface, func),
Matt Spinler69b0cf02020-10-14 10:59:03 -0500342 _serviceModeDelay(serviceModeDelay), _meltdownDelay(meltdownDelay)
343 {}
344
345 void start() override
346 {
347 // TODO
348 }
349
350 bool cancel(bool) override
351 {
352 // TODO
353 return true;
354 }
355
356 private:
357 std::chrono::seconds _serviceModeDelay;
358 std::chrono::seconds _meltdownDelay;
359};
360} // namespace phosphor::fan::monitor