#pragma once #include "power_button_profile.hpp" #include #include #include #include #include namespace phosphor::button { /** * @class HostThenChassisPowerOff * * A custom power button handler that will do the following: * * If power is off: * - A button press will power on as long as the BMC is * in the ready state. * * If power is on: * - A button press less than 4s won't do anything. * - At 4s, issue a host power off and start a 10s timer. * - If the button is released within that 10s and not pressed * again, continue with the host power off. * - If the button is released within that 10s and also * pressed again in that 10s, do a hard power (chassis) * off. * - If the button is pressed throughout that 10s * issue a hard power off. */ class HostThenChassisPowerOff : public PowerButtonProfile { public: enum class PowerOpState { powerOnPress, buttonNotPressed, buttonPressed, buttonPressedHostOffStarted, buttonReleasedHostToChassisOffWindow, chassisOffStarted }; /** * @brief Constructor * @param[in] bus - The sdbusplus bus object */ explicit HostThenChassisPowerOff(sdbusplus::bus_t& bus) : PowerButtonProfile(bus), state(PowerOpState::buttonNotPressed), timer(bus.get_event(), std::bind(&HostThenChassisPowerOff::timerHandler, this), pollInterval) { timer.setEnabled(false); } /** * @brief Returns the name that matches the value in * meson_options.txt. */ static constexpr std::string_view getName() { return "host_then_chassis_poweroff"; } HostThenChassisPowerOff() = delete; ~HostThenChassisPowerOff() = default; /** * @brief Called when the power button is pressed. */ virtual void pressed() override; /** * @brief Called when the power button is released. * * @param[in] pressTimeMS - How long the button was pressed * in milliseconds. */ virtual void released(uint64_t pressTimeMS) override; private: /** * @brief Determines if the BMC is in the ready state. * @return bool If the BMC is in the ready state */ bool isBmcReady() const; /** * @brief Determines if system (chassis) is powered on. * * @return bool - If power is on */ bool isPoweredOn() const; /** * @brief Requests a host state transition * @param[in] transition - The transition (like On or Off) */ void hostTransition( sdbusplus::xyz::openbmc_project::State::server::Host::Transition transition); /** * @brief Powers on the system */ void powerOn(); /** * @brief Requests a host power off */ void hostPowerOff(); /** * @brief Requests a chassis power off */ void chassisPowerOff(); /** * @brief The handler for the 1s timer that runs when determining * how to power off. * * A 1 second timer is used so that there is the ability to emit * a power off countdown if necessary. */ void timerHandler(); /** * @brief Sets the time the host will be powered off if the * button is still pressed - 4 seconds in the future. */ inline void setHostOffTime() { hostOffTime = std::chrono::steady_clock::now() + hostOffInterval; } /** * @brief Sets the time the chassis will be powered off if the * button is still pressed or pressed again - 10 seconds * in the future. */ inline void setChassisOffTime() { chassisOffTime = std::chrono::steady_clock::now() + chassisOffInterval; } /** * @brief The interval the timer handler is called at. */ static constexpr std::chrono::milliseconds pollInterval{1000}; /** * @brief Default button hold down interval constant */ static constexpr std::chrono::milliseconds hostOffInterval{4000}; /** * @brief The time between a host power off and chassis power off. */ static constexpr std::chrono::milliseconds chassisOffInterval{10000}; /** * @brief The current state of the handler. */ PowerOpState state; /** * @brief When the host will be powered off. */ std::chrono::time_point hostOffTime; /** * @brief When the chassis will be powered off. */ std::chrono::time_point chassisOffTime; /** * @brief The timer object. */ sdeventplus::utility::Timer timer; }; } // namespace phosphor::button