blob: f4b43fc235189f0d572f1f23b72946c97a2bfdb8 [file] [log] [blame]
Matt Spinlerfb35a322018-11-26 14:30:30 -06001#include "button_handler.hpp"
2
Matt Spinler963c65f2018-11-26 14:46:41 -06003#include <phosphor-logging/log.hpp>
4#include <xyz/openbmc_project/State/Chassis/server.hpp>
5#include <xyz/openbmc_project/State/Host/server.hpp>
6
Matt Spinlerfb35a322018-11-26 14:30:30 -06007namespace phosphor
8{
9namespace button
10{
Matt Spinler963c65f2018-11-26 14:46:41 -060011
12namespace sdbusRule = sdbusplus::bus::match::rules;
13using namespace sdbusplus::xyz::openbmc_project::State::server;
14using namespace phosphor::logging;
15using sdbusplus::exception::SdBusError;
16
17constexpr auto propertyIface = "org.freedesktop.DBus.Properties";
18constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis";
19constexpr auto hostIface = "xyz.openbmc_project.State.Host";
20constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power";
21constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
22
23constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
24constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
25
Matt Spinlerfb35a322018-11-26 14:30:30 -060026Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus)
27{
Matt Spinler963c65f2018-11-26 14:46:41 -060028 try
29 {
30 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty())
31 {
32 log<level::INFO>("Starting power button handler");
33 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
34 bus,
35 sdbusRule::type::signal() + sdbusRule::member("Released") +
36 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
37 sdbusRule::interface(powerButtonIface),
38 std::bind(std::mem_fn(&Handler::powerPressed), this,
39 std::placeholders::_1));
40
41 powerButtonLongPressReleased =
42 std::make_unique<sdbusplus::bus::match_t>(
43 bus,
44 sdbusRule::type::signal() +
45 sdbusRule::member("PressedLong") +
46 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
47 sdbusRule::interface(powerButtonIface),
48 std::bind(std::mem_fn(&Handler::longPowerPressed), this,
49 std::placeholders::_1));
50 }
51 }
52 catch (SdBusError& e)
53 {
54 // The button wasn't implemented
55 }
56}
57
58std::string Handler::getService(const std::string& path,
59 const std::string& interface) const
60{
61 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
62 "GetObject");
63 method.append(path, std::vector{interface});
64 auto result = bus.call(method);
65
66 std::map<std::string, std::vector<std::string>> objectData;
67 result.read(objectData);
68
69 return objectData.begin()->first;
70}
71
72bool Handler::poweredOn() const
73{
74 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
75 auto method = bus.new_method_call(
76 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Get");
77 method.append(chassisIface, "CurrentPowerState");
78 auto result = bus.call(method);
79
80 sdbusplus::message::variant<std::string> state;
81 result.read(state);
82
83 return Chassis::PowerState::On ==
84 Chassis::convertPowerStateFromString(
85 sdbusplus::message::variant_ns::get<std::string>(state));
86}
87
88void Handler::powerPressed(sdbusplus::message::message& msg)
89{
90 auto transition = Host::Transition::On;
91
92 try
93 {
94 if (poweredOn())
95 {
96 transition = Host::Transition::Off;
97 }
98
99 log<level::INFO>("Handling power button press");
100
101 sdbusplus::message::variant<std::string> state =
102 convertForMessage(transition);
103
104 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
105 auto method = bus.new_method_call(
106 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
107 method.append(hostIface, "RequestedHostTransition", state);
108
109 bus.call(method);
110 }
111 catch (SdBusError& e)
112 {
113 log<level::ERR>("Failed power state change on a power button press",
114 entry("ERROR=%s", e.what()));
115 }
116}
117
118void Handler::longPowerPressed(sdbusplus::message::message& msg)
119{
120 try
121 {
122 if (!poweredOn())
123 {
124 log<level::INFO>(
125 "Power is off so ignoring long power button press");
126 return;
127 }
128
129 log<level::INFO>("Handling long power button press");
130
131 sdbusplus::message::variant<std::string> state =
132 convertForMessage(Chassis::Transition::Off);
133
134 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
135 auto method = bus.new_method_call(
136 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set");
137 method.append(chassisIface, "RequestedPowerTransition", state);
138
139 bus.call(method);
140 }
141 catch (SdBusError& e)
142 {
143 log<level::ERR>("Failed powering off on long power button press",
144 entry("ERROR=%s", e.what()));
145 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600146}
147} // namespace button
148} // namespace phosphor