1 #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 11 namespace 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 */ 34 class 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 */ HostThenChassisPowerOff(sdbusplus::bus_t & bus)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 */ getName()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 */ setHostOffTime()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 */ setChassisOffTime()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 186