blob: 72231088a4ac981c2f0415ca77a5accfa8764a97 [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
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500124 std::variant<std::string> state;
Matt Spinler963c65f2018-11-26 14:46:41 -0600125 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
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500144 std::variant<std::string> state = convertForMessage(transition);
Matt Spinler963c65f2018-11-26 14:46:41 -0600145
146 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
147 auto method = bus.new_method_call(
148 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
149 method.append(hostIface, "RequestedHostTransition", state);
150
151 bus.call(method);
152 }
153 catch (SdBusError& e)
154 {
155 log<level::ERR>("Failed power state change on a power button press",
156 entry("ERROR=%s", e.what()));
157 }
158}
159
160void Handler::longPowerPressed(sdbusplus::message::message& msg)
161{
162 try
163 {
164 if (!poweredOn())
165 {
166 log<level::INFO>(
167 "Power is off so ignoring long power button press");
168 return;
169 }
170
171 log<level::INFO>("Handling long power button press");
172
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500173 std::variant<std::string> state =
Matt Spinler963c65f2018-11-26 14:46:41 -0600174 convertForMessage(Chassis::Transition::Off);
175
176 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface);
177 auto method = bus.new_method_call(
178 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set");
179 method.append(chassisIface, "RequestedPowerTransition", state);
180
181 bus.call(method);
182 }
183 catch (SdBusError& e)
184 {
185 log<level::ERR>("Failed powering off on long power button press",
186 entry("ERROR=%s", e.what()));
187 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600188}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600189
190void Handler::resetPressed(sdbusplus::message::message& msg)
191{
192 try
193 {
194 if (!poweredOn())
195 {
196 log<level::INFO>("Power is off so ignoring reset button press");
197 return;
198 }
199
200 log<level::INFO>("Handling reset button press");
201
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500202 std::variant<std::string> state =
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600203 convertForMessage(Host::Transition::Reboot);
204
205 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface);
206 auto method = bus.new_method_call(
207 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set");
208
209 method.append(hostIface, "RequestedHostTransition", state);
210
211 bus.call(method);
212 }
213 catch (SdBusError& e)
214 {
215 log<level::ERR>("Failed power state change on a reset button press",
216 entry("ERROR=%s", e.what()));
217 }
218}
Matt Spinler69f93512018-11-26 14:55:58 -0600219
220void Handler::idPressed(sdbusplus::message::message& msg)
221{
222 std::string groupPath{ledGroupBasePath};
223 groupPath += ID_LED_GROUP;
224
225 auto service = getService(groupPath, ledGroupIface);
226
227 if (service.empty())
228 {
229 log<level::INFO>("No identify LED group found during ID button press",
230 entry("GROUP=%s", groupPath.c_str()));
231 return;
232 }
233
234 try
235 {
236 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
237 propertyIface, "Get");
238 method.append(ledGroupIface, "Asserted");
239 auto result = bus.call(method);
240
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500241 std::variant<bool> state;
Matt Spinler69f93512018-11-26 14:55:58 -0600242 result.read(state);
243
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500244 state = !std::get<bool>(state);
Matt Spinler69f93512018-11-26 14:55:58 -0600245
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500246 log<level::INFO>("Changing ID LED group state on ID LED press",
247 entry("GROUP=%s", groupPath.c_str()),
248 entry("STATE=%d", std::get<bool>(state)));
Matt Spinler69f93512018-11-26 14:55:58 -0600249
250 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
251 propertyIface, "Set");
252
253 method.append(ledGroupIface, "Asserted", state);
254 result = bus.call(method);
255 }
256 catch (SdBusError& e)
257 {
258 log<level::ERR>("Error toggling ID LED group on ID button press",
259 entry("ERROR=%s", e.what()));
260 }
261}
Matt Spinlerfb35a322018-11-26 14:30:30 -0600262} // namespace button
263} // namespace phosphor