xref: /openbmc/phosphor-buttons/inc/host_then_chassis_poweroff.hpp (revision 31ce375e7e71ff6b3da460dc63c1ab4f16cf4df6)
11a309f77SMatt Spinler #pragma once
21a309f77SMatt Spinler #include "power_button_profile.hpp"
31a309f77SMatt Spinler 
41a309f77SMatt Spinler #include <sdbusplus/bus/match.hpp>
51a309f77SMatt Spinler #include <sdeventplus/event.hpp>
61a309f77SMatt Spinler #include <sdeventplus/utility/timer.hpp>
71a309f77SMatt Spinler #include <xyz/openbmc_project/State/Host/server.hpp>
81a309f77SMatt Spinler 
91a309f77SMatt Spinler #include <chrono>
101a309f77SMatt Spinler 
111a309f77SMatt Spinler namespace phosphor::button
121a309f77SMatt Spinler {
131a309f77SMatt Spinler 
141a309f77SMatt Spinler /**
151a309f77SMatt Spinler  * @class HostThenChassisPowerOff
161a309f77SMatt Spinler  *
171a309f77SMatt Spinler  * A custom power button handler that will do the following:
181a309f77SMatt Spinler  *
191a309f77SMatt Spinler  * If power is off:
201a309f77SMatt Spinler  *  - A button press will power on as long as the BMC is
211a309f77SMatt Spinler  *    in the ready state.
221a309f77SMatt Spinler  *
231a309f77SMatt Spinler  * If power is on:
241a309f77SMatt Spinler  *  - A button press less than 4s won't do anything.
251a309f77SMatt Spinler  *  - At 4s, issue a host power off and start a 10s timer.
261a309f77SMatt Spinler  *    - If the button is released within that 10s and not pressed
271a309f77SMatt Spinler  *      again, continue with the host power off.
281a309f77SMatt Spinler  *    - If the button is released within that 10s and also
291a309f77SMatt Spinler  *      pressed again in that 10s, do a hard power (chassis)
301a309f77SMatt Spinler  *      off.
311a309f77SMatt Spinler  *    - If the button is pressed throughout that 10s
321a309f77SMatt Spinler  *      issue a hard power off.
331a309f77SMatt Spinler  */
341a309f77SMatt Spinler class HostThenChassisPowerOff : public PowerButtonProfile
351a309f77SMatt Spinler {
361a309f77SMatt Spinler   public:
371a309f77SMatt Spinler     enum class PowerOpState
381a309f77SMatt Spinler     {
391a309f77SMatt Spinler         powerOnPress,
401a309f77SMatt Spinler         buttonNotPressed,
411a309f77SMatt Spinler         buttonPressed,
421a309f77SMatt Spinler         buttonPressedHostOffStarted,
431a309f77SMatt Spinler         buttonReleasedHostToChassisOffWindow,
441a309f77SMatt Spinler         chassisOffStarted
451a309f77SMatt Spinler     };
461a309f77SMatt Spinler 
471a309f77SMatt Spinler     /**
481a309f77SMatt Spinler      * @brief Constructor
491a309f77SMatt Spinler      * @param[in] bus - The sdbusplus bus object
501a309f77SMatt Spinler      */
HostThenChassisPowerOff(sdbusplus::bus_t & bus)511a309f77SMatt Spinler     explicit HostThenChassisPowerOff(sdbusplus::bus_t& bus) :
521a309f77SMatt Spinler         PowerButtonProfile(bus), state(PowerOpState::buttonNotPressed),
531a309f77SMatt Spinler         timer(bus.get_event(),
541a309f77SMatt Spinler               std::bind(&HostThenChassisPowerOff::timerHandler, this),
551a309f77SMatt Spinler               pollInterval)
561a309f77SMatt Spinler     {
571a309f77SMatt Spinler         timer.setEnabled(false);
581a309f77SMatt Spinler     }
591a309f77SMatt Spinler 
601a309f77SMatt Spinler     /**
611a309f77SMatt Spinler      * @brief Returns the name that matches the value in
621a309f77SMatt Spinler      *        meson_options.txt.
631a309f77SMatt Spinler      */
getName()64*31ce375eSRush Chen     static constexpr std::string getName()
651a309f77SMatt Spinler     {
661a309f77SMatt Spinler         return "host_then_chassis_poweroff";
671a309f77SMatt Spinler     }
681a309f77SMatt Spinler 
691a309f77SMatt Spinler     HostThenChassisPowerOff() = delete;
701a309f77SMatt Spinler     ~HostThenChassisPowerOff() = default;
711a309f77SMatt Spinler 
721a309f77SMatt Spinler     /**
731a309f77SMatt Spinler      * @brief Called when the power button is pressed.
741a309f77SMatt Spinler      */
751a309f77SMatt Spinler     virtual void pressed() override;
761a309f77SMatt Spinler 
771a309f77SMatt Spinler     /**
781a309f77SMatt Spinler      * @brief Called when the power button is released.
791a309f77SMatt Spinler      *
801a309f77SMatt Spinler      * @param[in] pressTimeMS - How long the button was pressed
811a309f77SMatt Spinler      *                          in milliseconds.
821a309f77SMatt Spinler      */
831a309f77SMatt Spinler     virtual void released(uint64_t pressTimeMS) override;
841a309f77SMatt Spinler 
851a309f77SMatt Spinler   private:
861a309f77SMatt Spinler     /**
871a309f77SMatt Spinler      * @brief Determines if the BMC is in the ready state.
881a309f77SMatt Spinler      * @return bool If the BMC is in the ready state
891a309f77SMatt Spinler      */
901a309f77SMatt Spinler     bool isBmcReady() const;
911a309f77SMatt Spinler 
921a309f77SMatt Spinler     /**
931a309f77SMatt Spinler      * @brief Determines if system (chassis) is powered on.
941a309f77SMatt Spinler      *
951a309f77SMatt Spinler      * @return bool - If power is on
961a309f77SMatt Spinler      */
971a309f77SMatt Spinler     bool isPoweredOn() const;
981a309f77SMatt Spinler 
991a309f77SMatt Spinler     /**
1001a309f77SMatt Spinler      * @brief Requests a host state transition
1011a309f77SMatt Spinler      * @param[in] transition - The transition (like On or Off)
1021a309f77SMatt Spinler      */
1031a309f77SMatt Spinler     void hostTransition(
1041a309f77SMatt Spinler         sdbusplus::xyz::openbmc_project::State::server::Host::Transition
1051a309f77SMatt Spinler             transition);
1061a309f77SMatt Spinler 
1071a309f77SMatt Spinler     /**
1081a309f77SMatt Spinler      * @brief Powers on the system
1091a309f77SMatt Spinler      */
1101a309f77SMatt Spinler     void powerOn();
1111a309f77SMatt Spinler 
1121a309f77SMatt Spinler     /**
1131a309f77SMatt Spinler      * @brief Requests a host power off
1141a309f77SMatt Spinler      */
1151a309f77SMatt Spinler     void hostPowerOff();
1161a309f77SMatt Spinler 
1171a309f77SMatt Spinler     /**
1181a309f77SMatt Spinler      * @brief Requests a chassis power off
1191a309f77SMatt Spinler      */
1201a309f77SMatt Spinler     void chassisPowerOff();
1211a309f77SMatt Spinler 
1221a309f77SMatt Spinler     /**
1231a309f77SMatt Spinler      * @brief The handler for the 1s timer that runs when determining
1241a309f77SMatt Spinler      *        how to power off.
1251a309f77SMatt Spinler      *
1261a309f77SMatt Spinler      * A 1 second timer is used so that there is the ability to emit
1271a309f77SMatt Spinler      * a power off countdown if necessary.
1281a309f77SMatt Spinler      */
1291a309f77SMatt Spinler     void timerHandler();
1301a309f77SMatt Spinler 
1311a309f77SMatt Spinler     /**
1321a309f77SMatt Spinler      * @brief Sets the time the host will be powered off if the
1331a309f77SMatt Spinler      *        button is still pressed - 4 seconds in the future.
1341a309f77SMatt Spinler      */
setHostOffTime()1351a309f77SMatt Spinler     inline void setHostOffTime()
1361a309f77SMatt Spinler     {
1371a309f77SMatt Spinler         hostOffTime = std::chrono::steady_clock::now() + hostOffInterval;
1381a309f77SMatt Spinler     }
1391a309f77SMatt Spinler 
1401a309f77SMatt Spinler     /**
1411a309f77SMatt Spinler      * @brief Sets the time the chassis will be powered off if the
1421a309f77SMatt Spinler      *        button is still pressed or pressed again - 10 seconds
1431a309f77SMatt Spinler      *        in the future.
1441a309f77SMatt Spinler      */
setChassisOffTime()1451a309f77SMatt Spinler     inline void setChassisOffTime()
1461a309f77SMatt Spinler     {
1471a309f77SMatt Spinler         chassisOffTime = std::chrono::steady_clock::now() + chassisOffInterval;
1481a309f77SMatt Spinler     }
1491a309f77SMatt Spinler 
1501a309f77SMatt Spinler     /**
1511a309f77SMatt Spinler      * @brief The interval the timer handler is called at.
1521a309f77SMatt Spinler      */
1531a309f77SMatt Spinler     static constexpr std::chrono::milliseconds pollInterval{1000};
1541a309f77SMatt Spinler 
1551a309f77SMatt Spinler     /**
1561a309f77SMatt Spinler      * @brief Default button hold down interval constant
1571a309f77SMatt Spinler      */
1581a309f77SMatt Spinler     static constexpr std::chrono::milliseconds hostOffInterval{4000};
1591a309f77SMatt Spinler 
1601a309f77SMatt Spinler     /**
1611a309f77SMatt Spinler      * @brief The time between a host power off and chassis power off.
1621a309f77SMatt Spinler      */
1631a309f77SMatt Spinler     static constexpr std::chrono::milliseconds chassisOffInterval{10000};
1641a309f77SMatt Spinler 
1651a309f77SMatt Spinler     /**
1661a309f77SMatt Spinler      * @brief The current state of the handler.
1671a309f77SMatt Spinler      */
1681a309f77SMatt Spinler     PowerOpState state;
1691a309f77SMatt Spinler 
1701a309f77SMatt Spinler     /**
1711a309f77SMatt Spinler      * @brief When the host will be powered off.
1721a309f77SMatt Spinler      */
1731a309f77SMatt Spinler     std::chrono::time_point<std::chrono::steady_clock> hostOffTime;
1741a309f77SMatt Spinler 
1751a309f77SMatt Spinler     /**
1761a309f77SMatt Spinler      * @brief When the chassis will be powered off.
1771a309f77SMatt Spinler      */
1781a309f77SMatt Spinler     std::chrono::time_point<std::chrono::steady_clock> chassisOffTime;
1791a309f77SMatt Spinler 
1801a309f77SMatt Spinler     /**
1811a309f77SMatt Spinler      * @brief The timer object.
1821a309f77SMatt Spinler      */
1831a309f77SMatt Spinler     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
1841a309f77SMatt Spinler };
1851a309f77SMatt Spinler } // namespace phosphor::button
186