blob: bc12d70291bdb5d644c85bdd3a678bdf2238807d [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 ==
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500128 Chassis::convertPowerStateFromString(std::get<std::string>(state));
Matt Spinler963c65f2018-11-26 14:46:41 -0600129}
130
131void Handler::powerPressed(sdbusplus::message::message& msg)
132{
133 auto transition = Host::Transition::On;
134
135 try
136 {
137 if (poweredOn())
138 {
139 transition = Host::Transition::Off;
140 }
141
142 log<level::INFO>("Handling power button press");
143
144 sdbusplus::message::variant<std::string> state =
145 convertForMessage(transition);
146
147 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
148 auto method = bus.new_method_call(
149 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
150 method.append(hostIface, "RequestedHostTransition", state);
151
152 bus.call(method);
153 }
154 catch (SdBusError& e)
155 {
156 log<level::ERR>("Failed power state change on a power button press",
157 entry("ERROR=%s", e.what()));
158 }
159}
160
161void Handler::longPowerPressed(sdbusplus::message::message& msg)
162{
163 try
164 {
165 if (!poweredOn())
166 {
167 log<level::INFO>(
168 "Power is off so ignoring long power button press");
169 return;
170 }
171
172 log<level::INFO>("Handling long power button press");
173
174 sdbusplus::message::variant<std::string> state =
175 convertForMessage(Chassis::Transition::Off);
176
177 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
178 auto method = bus.new_method_call(
179 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set");
180 method.append(chassisIface, "RequestedPowerTransition", state);
181
182 bus.call(method);
183 }
184 catch (SdBusError& e)
185 {
186 log<level::ERR>("Failed powering off on long power button press",
187 entry("ERROR=%s", e.what()));
188 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600189}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600190
191void Handler::resetPressed(sdbusplus::message::message& msg)
192{
193 try
194 {
195 if (!poweredOn())
196 {
197 log<level::INFO>("Power is off so ignoring reset button press");
198 return;
199 }
200
201 log<level::INFO>("Handling reset button press");
202
203 sdbusplus::message::variant<std::string> state =
204 convertForMessage(Host::Transition::Reboot);
205
206 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
207 auto method = bus.new_method_call(
208 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
209
210 method.append(hostIface, "RequestedHostTransition", state);
211
212 bus.call(method);
213 }
214 catch (SdBusError& e)
215 {
216 log<level::ERR>("Failed power state change on a reset button press",
217 entry("ERROR=%s", e.what()));
218 }
219}
Matt Spinler69f93512018-11-26 14:55:58 -0600220
221void Handler::idPressed(sdbusplus::message::message& msg)
222{
223 std::string groupPath{ledGroupBasePath};
224 groupPath += ID_LED_GROUP;
225
226 auto service = getService(groupPath, ledGroupIface);
227
228 if (service.empty())
229 {
230 log<level::INFO>("No identify LED group found during ID button press",
231 entry("GROUP=%s", groupPath.c_str()));
232 return;
233 }
234
235 try
236 {
237 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
238 propertyIface, "Get");
239 method.append(ledGroupIface, "Asserted");
240 auto result = bus.call(method);
241
242 sdbusplus::message::variant<bool> state;
243 result.read(state);
244
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500245 state = !std::get<bool>(state);
Matt Spinler69f93512018-11-26 14:55:58 -0600246
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500247 log<level::INFO>("Changing ID LED group state on ID LED press",
248 entry("GROUP=%s", groupPath.c_str()),
249 entry("STATE=%d", std::get<bool>(state)));
Matt Spinler69f93512018-11-26 14:55:58 -0600250
251 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
252 propertyIface, "Set");
253
254 method.append(ledGroupIface, "Asserted", state);
255 result = bus.call(method);
256 }
257 catch (SdBusError& e)
258 {
259 log<level::ERR>("Error toggling ID LED group on ID button press",
260 entry("ERROR=%s", e.what()));
261 }
262}
Matt Spinlerfb35a322018-11-26 14:30:30 -0600263} // namespace button
264} // namespace phosphor