blob: 96d7aee512546f93f6eb2ebace573fbca12f5c7b [file] [log] [blame]
Matt Spinler1a309f72023-04-04 13:12:19 -05001#pragma once
2#include "power_button_profile.hpp"
3
4#include <sdbusplus/bus/match.hpp>
5#include <sdeventplus/event.hpp>
6#include <sdeventplus/utility/timer.hpp>
7#include <xyz/openbmc_project/State/Host/server.hpp>
8
9#include <chrono>
10
11namespace phosphor::button
12{
13
14/**
15 * @class HostThenChassisPowerOff
16 *
17 * A custom power button handler that will do the following:
18 *
19 * If power is off:
20 * - A button press will power on as long as the BMC is
21 * in the ready state.
22 *
23 * If power is on:
24 * - A button press less than 4s won't do anything.
25 * - At 4s, issue a host power off and start a 10s timer.
26 * - If the button is released within that 10s and not pressed
27 * again, continue with the host power off.
28 * - If the button is released within that 10s and also
29 * pressed again in that 10s, do a hard power (chassis)
30 * off.
31 * - If the button is pressed throughout that 10s
32 * issue a hard power off.
33 */
34class HostThenChassisPowerOff : public PowerButtonProfile
35{
36 public:
37 enum class PowerOpState
38 {
39 powerOnPress,
40 buttonNotPressed,
41 buttonPressed,
42 buttonPressedHostOffStarted,
43 buttonReleasedHostToChassisOffWindow,
44 chassisOffStarted
45 };
46
47 /**
48 * @brief Constructor
49 * @param[in] bus - The sdbusplus bus object
50 */
51 explicit HostThenChassisPowerOff(sdbusplus::bus_t& bus) :
52 PowerButtonProfile(bus), state(PowerOpState::buttonNotPressed),
53 timer(bus.get_event(),
54 std::bind(&HostThenChassisPowerOff::timerHandler, this),
55 pollInterval)
56 {
57 timer.setEnabled(false);
58 }
59
60 /**
61 * @brief Returns the name that matches the value in
62 * meson_options.txt.
63 */
64 static constexpr std::string_view getName()
65 {
66 return "host_then_chassis_poweroff";
67 }
68
69 HostThenChassisPowerOff() = delete;
70 ~HostThenChassisPowerOff() = default;
71
72 /**
73 * @brief Called when the power button is pressed.
74 */
75 virtual void pressed() override;
76
77 /**
78 * @brief Called when the power button is released.
79 *
80 * @param[in] pressTimeMS - How long the button was pressed
81 * in milliseconds.
82 */
83 virtual void released(uint64_t pressTimeMS) override;
84
85 private:
86 /**
87 * @brief Determines if the BMC is in the ready state.
88 * @return bool If the BMC is in the ready state
89 */
90 bool isBmcReady() const;
91
92 /**
93 * @brief Determines if system (chassis) is powered on.
94 *
95 * @return bool - If power is on
96 */
97 bool isPoweredOn() const;
98
99 /**
100 * @brief Requests a host state transition
101 * @param[in] transition - The transition (like On or Off)
102 */
103 void hostTransition(
104 sdbusplus::xyz::openbmc_project::State::server::Host::Transition
105 transition);
106
107 /**
108 * @brief Powers on the system
109 */
110 void powerOn();
111
112 /**
113 * @brief Requests a host power off
114 */
115 void hostPowerOff();
116
117 /**
118 * @brief Requests a chassis power off
119 */
120 void chassisPowerOff();
121
122 /**
123 * @brief The handler for the 1s timer that runs when determining
124 * how to power off.
125 *
126 * A 1 second timer is used so that there is the ability to emit
127 * a power off countdown if necessary.
128 */
129 void timerHandler();
130
131 /**
132 * @brief Sets the time the host will be powered off if the
133 * button is still pressed - 4 seconds in the future.
134 */
135 inline void setHostOffTime()
136 {
137 hostOffTime = std::chrono::steady_clock::now() + hostOffInterval;
138 }
139
140 /**
141 * @brief Sets the time the chassis will be powered off if the
142 * button is still pressed or pressed again - 10 seconds
143 * in the future.
144 */
145 inline void setChassisOffTime()
146 {
147 chassisOffTime = std::chrono::steady_clock::now() + chassisOffInterval;
148 }
149
150 /**
151 * @brief The interval the timer handler is called at.
152 */
153 static constexpr std::chrono::milliseconds pollInterval{1000};
154
155 /**
156 * @brief Default button hold down interval constant
157 */
158 static constexpr std::chrono::milliseconds hostOffInterval{4000};
159
160 /**
161 * @brief The time between a host power off and chassis power off.
162 */
163 static constexpr std::chrono::milliseconds chassisOffInterval{10000};
164
165 /**
166 * @brief The current state of the handler.
167 */
168 PowerOpState state;
169
170 /**
171 * @brief When the host will be powered off.
172 */
173 std::chrono::time_point<std::chrono::steady_clock> hostOffTime;
174
175 /**
176 * @brief When the chassis will be powered off.
177 */
178 std::chrono::time_point<std::chrono::steady_clock> chassisOffTime;
179
180 /**
181 * @brief The timer object.
182 */
183 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
184};
185} // namespace phosphor::button