blob: f4b43fc235189f0d572f1f23b72946c97a2bfdb8 [file] [log] [blame]
#include "button_handler.hpp"
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/State/Chassis/server.hpp>
#include <xyz/openbmc_project/State/Host/server.hpp>
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<level::INFO>("Starting power button handler");
powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
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<sdbusplus::bus::match_t>(
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<std::string, std::vector<std::string>> 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<std::string> state;
result.read(state);
return Chassis::PowerState::On ==
Chassis::convertPowerStateFromString(
sdbusplus::message::variant_ns::get<std::string>(state));
}
void Handler::powerPressed(sdbusplus::message::message& msg)
{
auto transition = Host::Transition::On;
try
{
if (poweredOn())
{
transition = Host::Transition::Off;
}
log<level::INFO>("Handling power button press");
sdbusplus::message::variant<std::string> 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<level::ERR>("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<level::INFO>(
"Power is off so ignoring long power button press");
return;
}
log<level::INFO>("Handling long power button press");
sdbusplus::message::variant<std::string> 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<level::ERR>("Failed powering off on long power button press",
entry("ERROR=%s", e.what()));
}
}
} // namespace button
} // namespace phosphor