1 /** 2 * Copyright © 2021 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "power_interface.hpp" 18 19 #include "types.hpp" 20 21 #include <fmt/format.h> 22 23 #include <phosphor-logging/log.hpp> 24 #include <sdbusplus/exception.hpp> 25 #include <sdbusplus/sdbus.hpp> 26 #include <sdbusplus/server.hpp> 27 28 #include <string> 29 #include <tuple> 30 31 using namespace phosphor::logging; 32 33 namespace phosphor::power::sequencer 34 { 35 36 PowerInterface::PowerInterface(sdbusplus::bus::bus& bus, const char* path) : 37 _serverInterface(bus, path, POWER_IFACE, _vtable, this) 38 {} 39 40 int PowerInterface::callbackGetPgood(sd_bus* /*bus*/, const char* /*path*/, 41 const char* /*interface*/, 42 const char* /*property*/, 43 sd_bus_message* msg, void* context, 44 sd_bus_error* error) 45 { 46 if (msg != nullptr && context != nullptr) 47 { 48 try 49 { 50 auto pwrObj = static_cast<PowerInterface*>(context); 51 int pgood = pwrObj->getPgood(); 52 log<level::INFO>( 53 fmt::format("callbackGetPgood: {}", pgood).c_str()); 54 55 sdbusplus::message::message(msg).append(pgood); 56 } 57 catch (sdbusplus::exception_t& e) 58 { 59 return sd_bus_error_set(error, e.name(), e.description()); 60 } 61 } 62 else 63 { 64 // The message or context were null 65 log<level::ERR>("Unable to service get pgood property callback"); 66 return -1; 67 } 68 69 return 1; 70 } 71 72 int PowerInterface::callbackGetPgoodTimeout(sd_bus* /*bus*/, 73 const char* /*path*/, 74 const char* /*interface*/, 75 const char* /*property*/, 76 sd_bus_message* msg, void* context, 77 sd_bus_error* error) 78 { 79 if (msg != nullptr && context != nullptr) 80 { 81 try 82 { 83 auto pwrObj = static_cast<PowerInterface*>(context); 84 int timeout = pwrObj->getPgoodTimeout(); 85 log<level::INFO>( 86 fmt::format("callbackGetPgoodTimeout: {}", timeout).c_str()); 87 88 sdbusplus::message::message(msg).append(timeout); 89 } 90 catch (sdbusplus::exception_t& e) 91 { 92 return sd_bus_error_set(error, e.name(), e.description()); 93 } 94 } 95 else 96 { 97 // The message or context were null 98 log<level::ERR>( 99 "Unable to service get pgood timeout property callback"); 100 return -1; 101 } 102 103 return 1; 104 } 105 106 int PowerInterface::callbackGetPowerState(sd_bus_message* msg, void* context, 107 sd_bus_error* error) 108 { 109 if (msg != nullptr && context != nullptr) 110 { 111 try 112 { 113 auto pwrObj = static_cast<PowerInterface*>(context); 114 // Return the current power state of the GPIO, rather than the last 115 // requested power state change 116 int pgood = pwrObj->getPgood(); 117 log<level::INFO>( 118 fmt::format("callbackGetPowerState: {}", pgood).c_str()); 119 120 auto reply = sdbusplus::message::message(msg).new_method_return(); 121 reply.append(pgood); 122 reply.method_return(); 123 } 124 catch (sdbusplus::exception_t& e) 125 { 126 return sd_bus_error_set(error, e.name(), e.description()); 127 } 128 } 129 else 130 { 131 // The message or context were null 132 log<level::ERR>("Unable to service getPowerState method callback"); 133 return -1; 134 } 135 136 return 1; 137 } 138 139 int PowerInterface::callbackSetPgoodTimeout(sd_bus* /*bus*/, 140 const char* /*path*/, 141 const char* /*interface*/, 142 const char* /*property*/, 143 sd_bus_message* msg, void* context, 144 sd_bus_error* error) 145 { 146 if (msg != nullptr && context != nullptr) 147 { 148 try 149 { 150 auto m = sdbusplus::message::message(msg); 151 152 int timeout{}; 153 m.read(timeout); 154 155 auto pwrObj = static_cast<PowerInterface*>(context); 156 log<level::INFO>( 157 fmt::format("callbackSetPgoodTimeout: {}", timeout).c_str()); 158 pwrObj->setPgoodTimeout(timeout); 159 } 160 catch (sdbusplus::exception_t& e) 161 { 162 return sd_bus_error_set(error, e.name(), e.description()); 163 } 164 } 165 else 166 { 167 // The message or context were null 168 log<level::ERR>( 169 "Unable to service set pgood timeout property callback"); 170 return -1; 171 } 172 173 return 1; 174 } 175 176 int PowerInterface::callbackGetState(sd_bus* /*bus*/, const char* /*path*/, 177 const char* /*interface*/, 178 const char* /*property*/, 179 sd_bus_message* msg, void* context, 180 sd_bus_error* error) 181 { 182 if (msg != nullptr && context != nullptr) 183 { 184 try 185 { 186 auto pwrObj = static_cast<PowerInterface*>(context); 187 int state = pwrObj->getState(); 188 log<level::INFO>( 189 fmt::format("callbackGetState: {}", state).c_str()); 190 191 sdbusplus::message::message(msg).append(state); 192 } 193 catch (sdbusplus::exception_t& e) 194 { 195 return sd_bus_error_set(error, e.name(), e.description()); 196 } 197 } 198 else 199 { 200 // The message or context were null 201 log<level::ERR>("Unable to service get state property callback"); 202 return -1; 203 } 204 205 return 1; 206 } 207 208 int PowerInterface::callbackSetPowerState(sd_bus_message* msg, void* context, 209 sd_bus_error* error) 210 { 211 if (msg != nullptr && context != nullptr) 212 { 213 try 214 { 215 auto m = sdbusplus::message::message(msg); 216 217 int state{}; 218 m.read(state); 219 220 if (state != 1 && state != 0) 221 { 222 return sd_bus_error_set(error, 223 "org.openbmc.ControlPower.Error.Failed", 224 "Invalid power state"); 225 } 226 227 auto pwrObj = static_cast<PowerInterface*>(context); 228 log<level::INFO>( 229 fmt::format("callbackSetPowerState: {}", state).c_str()); 230 pwrObj->setState(state); 231 232 m.new_method_return().method_return(); 233 } 234 catch (sdbusplus::exception_t& e) 235 { 236 return sd_bus_error_set(error, e.name(), e.description()); 237 } 238 } 239 else 240 { 241 // The message or context were null 242 log<level::ERR>("Unable to service setPowerState method callback"); 243 return -1; 244 } 245 246 return 1; 247 } 248 249 void PowerInterface::emitPowerGoodSignal() 250 { 251 log<level::INFO>("emitPowerGoodSignal"); 252 _serverInterface.new_signal("PowerGood").signal_send(); 253 } 254 255 void PowerInterface::emitPowerLostSignal() 256 { 257 log<level::INFO>("emitPowerLostSignal"); 258 _serverInterface.new_signal("PowerLost").signal_send(); 259 } 260 261 void PowerInterface::emitPropertyChangedSignal(const char* property) 262 { 263 log<level::INFO>( 264 fmt::format("emitPropertyChangedSignal: {}", property).c_str()); 265 _serverInterface.property_changed(property); 266 } 267 268 const sdbusplus::vtable::vtable_t PowerInterface::_vtable[] = { 269 sdbusplus::vtable::start(), 270 // Method setPowerState takes an int parameter and returns void 271 sdbusplus::vtable::method("setPowerState", "i", "", callbackSetPowerState), 272 // Method getPowerState takes no parameters and returns int 273 sdbusplus::vtable::method("getPowerState", "", "i", callbackGetPowerState), 274 // Signal PowerGood 275 sdbusplus::vtable::signal("PowerGood", ""), 276 // Signal PowerLost 277 sdbusplus::vtable::signal("PowerLost", ""), 278 // Property pgood is type int, read only, and uses the emits_change flag 279 sdbusplus::vtable::property("pgood", "i", callbackGetPgood, 280 sdbusplus::vtable::property_::emits_change), 281 // Property state is type int, read only, and uses the emits_change flag 282 sdbusplus::vtable::property("state", "i", callbackGetState, 283 sdbusplus::vtable::property_::emits_change), 284 // Property pgood_timeout is type int, read write, and uses the emits_change 285 // flag 286 sdbusplus::vtable::property("pgood_timeout", "i", callbackGetPgoodTimeout, 287 callbackSetPgoodTimeout, 288 sdbusplus::vtable::property_::emits_change), 289 sdbusplus::vtable::end()}; 290 291 } // namespace phosphor::power::sequencer 292