#include "button_handler.hpp" #include #include #include namespace phosphor { namespace button { namespace sdbusRule = sdbusplus::bus::match::rules; using namespace sdbusplus::xyz::openbmc_project::State::server; using namespace phosphor::logging; using sdbusplus::exception::SdBusError; constexpr auto propertyIface = "org.freedesktop.DBus.Properties"; constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis"; constexpr auto hostIface = "xyz.openbmc_project.State.Host"; constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power"; constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper"; constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper"; constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper"; Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus) { try { if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty()) { log("Starting power button handler"); powerButtonReleased = std::make_unique( bus, sdbusRule::type::signal() + sdbusRule::member("Released") + sdbusRule::path(POWER_DBUS_OBJECT_NAME) + sdbusRule::interface(powerButtonIface), std::bind(std::mem_fn(&Handler::powerPressed), this, std::placeholders::_1)); powerButtonLongPressReleased = std::make_unique( bus, sdbusRule::type::signal() + sdbusRule::member("PressedLong") + sdbusRule::path(POWER_DBUS_OBJECT_NAME) + sdbusRule::interface(powerButtonIface), std::bind(std::mem_fn(&Handler::longPowerPressed), this, std::placeholders::_1)); } } catch (SdBusError& e) { // The button wasn't implemented } } std::string Handler::getService(const std::string& path, const std::string& interface) const { auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface, "GetObject"); method.append(path, std::vector{interface}); auto result = bus.call(method); std::map> objectData; result.read(objectData); return objectData.begin()->first; } bool Handler::poweredOn() const { auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface); auto method = bus.new_method_call( service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Get"); method.append(chassisIface, "CurrentPowerState"); auto result = bus.call(method); sdbusplus::message::variant state; result.read(state); return Chassis::PowerState::On == Chassis::convertPowerStateFromString( sdbusplus::message::variant_ns::get(state)); } void Handler::powerPressed(sdbusplus::message::message& msg) { auto transition = Host::Transition::On; try { if (poweredOn()) { transition = Host::Transition::Off; } log("Handling power button press"); sdbusplus::message::variant state = convertForMessage(transition); auto service = getService(HOST_STATE_OBJECT_NAME, hostIface); auto method = bus.new_method_call( service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set"); method.append(hostIface, "RequestedHostTransition", state); bus.call(method); } catch (SdBusError& e) { log("Failed power state change on a power button press", entry("ERROR=%s", e.what())); } } void Handler::longPowerPressed(sdbusplus::message::message& msg) { try { if (!poweredOn()) { log( "Power is off so ignoring long power button press"); return; } log("Handling long power button press"); sdbusplus::message::variant state = convertForMessage(Chassis::Transition::Off); auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface); auto method = bus.new_method_call( service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set"); method.append(chassisIface, "RequestedPowerTransition", state); bus.call(method); } catch (SdBusError& e) { log("Failed powering off on long power button press", entry("ERROR=%s", e.what())); } } } // namespace button } // namespace phosphor