1 #include "button_handler.hpp" 2 3 #include "settings.hpp" 4 5 #include <phosphor-logging/log.hpp> 6 #include <xyz/openbmc_project/State/Chassis/server.hpp> 7 #include <xyz/openbmc_project/State/Host/server.hpp> 8 9 namespace phosphor 10 { 11 namespace button 12 { 13 14 namespace sdbusRule = sdbusplus::bus::match::rules; 15 using namespace sdbusplus::xyz::openbmc_project::State::server; 16 using namespace phosphor::logging; 17 using sdbusplus::exception::SdBusError; 18 19 constexpr auto propertyIface = "org.freedesktop.DBus.Properties"; 20 constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis"; 21 constexpr auto hostIface = "xyz.openbmc_project.State.Host"; 22 constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power"; 23 constexpr auto idButtonIface = "xyz.openbmc_project.Chassis.Buttons.ID"; 24 constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset"; 25 constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper"; 26 constexpr auto ledGroupIface = "xyz.openbmc_project.Led.Group"; 27 28 constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper"; 29 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper"; 30 constexpr auto ledGroupBasePath = "/xyz/openbmc_project/led/groups/"; 31 32 Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus) 33 { 34 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 } 62 63 try 64 { 65 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 { 84 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 } 100 } 101 102 std::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 116 bool 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 132 void 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 162 void 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 } 190 } 191 192 void 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 } 221 222 void 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 } 266 } // namespace button 267 } // namespace phosphor 268