blob: e31db4ba3cdc3d278ae07d6263048d42e8088756 [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";
Matt Spinler06a5bdd2018-11-26 14:50:48 -060021constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset";
Matt Spinler963c65f2018-11-26 14:46:41 -060022constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
23
24constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
25constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
26
Matt Spinlerfb35a322018-11-26 14:30:30 -060027Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus)
28{
Matt Spinler963c65f2018-11-26 14:46:41 -060029 try
30 {
31 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty())
32 {
33 log<level::INFO>("Starting power button handler");
34 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
35 bus,
36 sdbusRule::type::signal() + sdbusRule::member("Released") +
37 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
38 sdbusRule::interface(powerButtonIface),
39 std::bind(std::mem_fn(&Handler::powerPressed), this,
40 std::placeholders::_1));
41
42 powerButtonLongPressReleased =
43 std::make_unique<sdbusplus::bus::match_t>(
44 bus,
45 sdbusRule::type::signal() +
46 sdbusRule::member("PressedLong") +
47 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
48 sdbusRule::interface(powerButtonIface),
49 std::bind(std::mem_fn(&Handler::longPowerPressed), this,
50 std::placeholders::_1));
51 }
52 }
53 catch (SdBusError& e)
54 {
55 // The button wasn't implemented
56 }
Matt Spinler06a5bdd2018-11-26 14:50:48 -060057
58 try
59 {
60 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
61 {
62 log<level::INFO>("Registering reset button handler");
63 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
64 bus,
65 sdbusRule::type::signal() + sdbusRule::member("Released") +
66 sdbusRule::path(RESET_DBUS_OBJECT_NAME) +
67 sdbusRule::interface(resetButtonIface),
68 std::bind(std::mem_fn(&Handler::resetPressed), this,
69 std::placeholders::_1));
70 }
71 }
72 catch (SdBusError& e)
73 {
74 // The button wasn't implemented
75 }
Matt Spinler963c65f2018-11-26 14:46:41 -060076}
77
78std::string Handler::getService(const std::string& path,
79 const std::string& interface) const
80{
81 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
82 "GetObject");
83 method.append(path, std::vector{interface});
84 auto result = bus.call(method);
85
86 std::map<std::string, std::vector<std::string>> objectData;
87 result.read(objectData);
88
89 return objectData.begin()->first;
90}
91
92bool Handler::poweredOn() const
93{
94 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
95 auto method = bus.new_method_call(
96 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Get");
97 method.append(chassisIface, "CurrentPowerState");
98 auto result = bus.call(method);
99
100 sdbusplus::message::variant<std::string> state;
101 result.read(state);
102
103 return Chassis::PowerState::On ==
104 Chassis::convertPowerStateFromString(
105 sdbusplus::message::variant_ns::get<std::string>(state));
106}
107
108void Handler::powerPressed(sdbusplus::message::message& msg)
109{
110 auto transition = Host::Transition::On;
111
112 try
113 {
114 if (poweredOn())
115 {
116 transition = Host::Transition::Off;
117 }
118
119 log<level::INFO>("Handling power button press");
120
121 sdbusplus::message::variant<std::string> state =
122 convertForMessage(transition);
123
124 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
125 auto method = bus.new_method_call(
126 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
127 method.append(hostIface, "RequestedHostTransition", state);
128
129 bus.call(method);
130 }
131 catch (SdBusError& e)
132 {
133 log<level::ERR>("Failed power state change on a power button press",
134 entry("ERROR=%s", e.what()));
135 }
136}
137
138void Handler::longPowerPressed(sdbusplus::message::message& msg)
139{
140 try
141 {
142 if (!poweredOn())
143 {
144 log<level::INFO>(
145 "Power is off so ignoring long power button press");
146 return;
147 }
148
149 log<level::INFO>("Handling long power button press");
150
151 sdbusplus::message::variant<std::string> state =
152 convertForMessage(Chassis::Transition::Off);
153
154 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
155 auto method = bus.new_method_call(
156 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set");
157 method.append(chassisIface, "RequestedPowerTransition", state);
158
159 bus.call(method);
160 }
161 catch (SdBusError& e)
162 {
163 log<level::ERR>("Failed powering off on long power button press",
164 entry("ERROR=%s", e.what()));
165 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600166}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600167
168void Handler::resetPressed(sdbusplus::message::message& msg)
169{
170 try
171 {
172 if (!poweredOn())
173 {
174 log<level::INFO>("Power is off so ignoring reset button press");
175 return;
176 }
177
178 log<level::INFO>("Handling reset button press");
179
180 sdbusplus::message::variant<std::string> state =
181 convertForMessage(Host::Transition::Reboot);
182
183 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
184 auto method = bus.new_method_call(
185 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
186
187 method.append(hostIface, "RequestedHostTransition", state);
188
189 bus.call(method);
190 }
191 catch (SdBusError& e)
192 {
193 log<level::ERR>("Failed power state change on a reset button press",
194 entry("ERROR=%s", e.what()));
195 }
196}
Matt Spinlerfb35a322018-11-26 14:30:30 -0600197} // namespace button
198} // namespace phosphor