blob: 675f1ea81d39deb0a8de34364fd3569e40b7dfeb [file] [log] [blame]
Matt Spinlerfb35a322018-11-26 14:30:30 -06001#include "button_handler.hpp"
2
Matt Spinler69f93512018-11-26 14:55:58 -06003#include "settings.hpp"
4
Matt Spinler963c65f2018-11-26 14:46:41 -06005#include <phosphor-logging/log.hpp>
6#include <xyz/openbmc_project/State/Chassis/server.hpp>
7#include <xyz/openbmc_project/State/Host/server.hpp>
8
Matt Spinlerfb35a322018-11-26 14:30:30 -06009namespace phosphor
10{
11namespace button
12{
Matt Spinler963c65f2018-11-26 14:46:41 -060013
14namespace sdbusRule = sdbusplus::bus::match::rules;
15using namespace sdbusplus::xyz::openbmc_project::State::server;
16using namespace phosphor::logging;
17using sdbusplus::exception::SdBusError;
18
19constexpr auto propertyIface = "org.freedesktop.DBus.Properties";
20constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis";
21constexpr auto hostIface = "xyz.openbmc_project.State.Host";
22constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power";
Matt Spinler69f93512018-11-26 14:55:58 -060023constexpr auto idButtonIface = "xyz.openbmc_project.Chassis.Buttons.ID";
Matt Spinler06a5bdd2018-11-26 14:50:48 -060024constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset";
Matt Spinler963c65f2018-11-26 14:46:41 -060025constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
Matt Spinler69f93512018-11-26 14:55:58 -060026constexpr auto ledGroupIface = "xyz.openbmc_project.Led.Group";
Matt Spinler963c65f2018-11-26 14:46:41 -060027
28constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
29constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
Matt Spinler69f93512018-11-26 14:55:58 -060030constexpr auto ledGroupBasePath = "/xyz/openbmc_project/led/groups/";
Matt Spinler963c65f2018-11-26 14:46:41 -060031
Matt Spinlerfb35a322018-11-26 14:30:30 -060032Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus)
33{
Matt Spinler963c65f2018-11-26 14:46:41 -060034 try
35 {
36 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty())
37 {
38 log<level::INFO>("Starting power button handler");
39 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
40 bus,
41 sdbusRule::type::signal() + sdbusRule::member("Released") +
42 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
43 sdbusRule::interface(powerButtonIface),
44 std::bind(std::mem_fn(&Handler::powerPressed), this,
45 std::placeholders::_1));
46
47 powerButtonLongPressReleased =
48 std::make_unique<sdbusplus::bus::match_t>(
49 bus,
50 sdbusRule::type::signal() +
51 sdbusRule::member("PressedLong") +
52 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
53 sdbusRule::interface(powerButtonIface),
54 std::bind(std::mem_fn(&Handler::longPowerPressed), this,
55 std::placeholders::_1));
56 }
57 }
58 catch (SdBusError& e)
59 {
60 // The button wasn't implemented
61 }
Matt Spinler06a5bdd2018-11-26 14:50:48 -060062
63 try
64 {
Matt Spinler69f93512018-11-26 14:55:58 -060065 if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty())
66 {
67 log<level::INFO>("Registering ID button handler");
68 idButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
69 bus,
70 sdbusRule::type::signal() + sdbusRule::member("Released") +
71 sdbusRule::path(ID_DBUS_OBJECT_NAME) +
72 sdbusRule::interface(idButtonIface),
73 std::bind(std::mem_fn(&Handler::idPressed), this,
74 std::placeholders::_1));
75 }
76 }
77 catch (SdBusError& e)
78 {
79 // The button wasn't implemented
80 }
81
82 try
83 {
Matt Spinler06a5bdd2018-11-26 14:50:48 -060084 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
85 {
86 log<level::INFO>("Registering reset button handler");
87 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
88 bus,
89 sdbusRule::type::signal() + sdbusRule::member("Released") +
90 sdbusRule::path(RESET_DBUS_OBJECT_NAME) +
91 sdbusRule::interface(resetButtonIface),
92 std::bind(std::mem_fn(&Handler::resetPressed), this,
93 std::placeholders::_1));
94 }
95 }
96 catch (SdBusError& e)
97 {
98 // The button wasn't implemented
99 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600100}
101
102std::string Handler::getService(const std::string& path,
103 const std::string& interface) const
104{
105 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
106 "GetObject");
107 method.append(path, std::vector{interface});
108 auto result = bus.call(method);
109
110 std::map<std::string, std::vector<std::string>> objectData;
111 result.read(objectData);
112
113 return objectData.begin()->first;
114}
115
116bool Handler::poweredOn() const
117{
118 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
119 auto method = bus.new_method_call(
120 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Get");
121 method.append(chassisIface, "CurrentPowerState");
122 auto result = bus.call(method);
123
124 sdbusplus::message::variant<std::string> state;
125 result.read(state);
126
127 return Chassis::PowerState::On ==
128 Chassis::convertPowerStateFromString(
129 sdbusplus::message::variant_ns::get<std::string>(state));
130}
131
132void Handler::powerPressed(sdbusplus::message::message& msg)
133{
134 auto transition = Host::Transition::On;
135
136 try
137 {
138 if (poweredOn())
139 {
140 transition = Host::Transition::Off;
141 }
142
143 log<level::INFO>("Handling power button press");
144
145 sdbusplus::message::variant<std::string> state =
146 convertForMessage(transition);
147
148 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
149 auto method = bus.new_method_call(
150 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
151 method.append(hostIface, "RequestedHostTransition", state);
152
153 bus.call(method);
154 }
155 catch (SdBusError& e)
156 {
157 log<level::ERR>("Failed power state change on a power button press",
158 entry("ERROR=%s", e.what()));
159 }
160}
161
162void Handler::longPowerPressed(sdbusplus::message::message& msg)
163{
164 try
165 {
166 if (!poweredOn())
167 {
168 log<level::INFO>(
169 "Power is off so ignoring long power button press");
170 return;
171 }
172
173 log<level::INFO>("Handling long power button press");
174
175 sdbusplus::message::variant<std::string> state =
176 convertForMessage(Chassis::Transition::Off);
177
178 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
179 auto method = bus.new_method_call(
180 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set");
181 method.append(chassisIface, "RequestedPowerTransition", state);
182
183 bus.call(method);
184 }
185 catch (SdBusError& e)
186 {
187 log<level::ERR>("Failed powering off on long power button press",
188 entry("ERROR=%s", e.what()));
189 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600190}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600191
192void Handler::resetPressed(sdbusplus::message::message& msg)
193{
194 try
195 {
196 if (!poweredOn())
197 {
198 log<level::INFO>("Power is off so ignoring reset button press");
199 return;
200 }
201
202 log<level::INFO>("Handling reset button press");
203
204 sdbusplus::message::variant<std::string> state =
205 convertForMessage(Host::Transition::Reboot);
206
207 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
208 auto method = bus.new_method_call(
209 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
210
211 method.append(hostIface, "RequestedHostTransition", state);
212
213 bus.call(method);
214 }
215 catch (SdBusError& e)
216 {
217 log<level::ERR>("Failed power state change on a reset button press",
218 entry("ERROR=%s", e.what()));
219 }
220}
Matt Spinler69f93512018-11-26 14:55:58 -0600221
222void Handler::idPressed(sdbusplus::message::message& msg)
223{
224 std::string groupPath{ledGroupBasePath};
225 groupPath += ID_LED_GROUP;
226
227 auto service = getService(groupPath, ledGroupIface);
228
229 if (service.empty())
230 {
231 log<level::INFO>("No identify LED group found during ID button press",
232 entry("GROUP=%s", groupPath.c_str()));
233 return;
234 }
235
236 try
237 {
238 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
239 propertyIface, "Get");
240 method.append(ledGroupIface, "Asserted");
241 auto result = bus.call(method);
242
243 sdbusplus::message::variant<bool> state;
244 result.read(state);
245
246 state = !sdbusplus::message::variant_ns::get<bool>(state);
247
248 log<level::INFO>(
249 "Changing ID LED group state on ID LED press",
250 entry("GROUP=%s", groupPath.c_str()),
251 entry("STATE=%d",
252 sdbusplus::message::variant_ns::get<bool>(state)));
253
254 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
255 propertyIface, "Set");
256
257 method.append(ledGroupIface, "Asserted", state);
258 result = bus.call(method);
259 }
260 catch (SdBusError& e)
261 {
262 log<level::ERR>("Error toggling ID LED group on ID button press",
263 entry("ERROR=%s", e.what()));
264 }
265}
Matt Spinlerfb35a322018-11-26 14:30:30 -0600266} // namespace button
267} // namespace phosphor