blob: 96d7aee512546f93f6eb2ebace573fbca12f5c7b [file] [log] [blame]
#pragma once
#include "power_button_profile.hpp"
#include <sdbusplus/bus/match.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <xyz/openbmc_project/State/Host/server.hpp>
#include <chrono>
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<std::chrono::steady_clock> hostOffTime;
/**
* @brief When the chassis will be powered off.
*/
std::chrono::time_point<std::chrono::steady_clock> chassisOffTime;
/**
* @brief The timer object.
*/
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
};
} // namespace phosphor::button