| /** | 
 |  * Copyright © 2021 IBM Corporation | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "power_interface.hpp" | 
 |  | 
 | #include "types.hpp" | 
 |  | 
 | #include <fmt/format.h> | 
 |  | 
 | #include <phosphor-logging/log.hpp> | 
 | #include <sdbusplus/exception.hpp> | 
 | #include <sdbusplus/sdbus.hpp> | 
 | #include <sdbusplus/server.hpp> | 
 |  | 
 | #include <string> | 
 | #include <tuple> | 
 |  | 
 | using namespace phosphor::logging; | 
 |  | 
 | namespace phosphor::power::sequencer | 
 | { | 
 |  | 
 | PowerInterface::PowerInterface(sdbusplus::bus_t& bus, const char* path) : | 
 |     serverInterface(bus, path, POWER_IFACE, vtable, this) | 
 | {} | 
 |  | 
 | int PowerInterface::callbackGetPgood(sd_bus* /*bus*/, const char* /*path*/, | 
 |                                      const char* /*interface*/, | 
 |                                      const char* /*property*/, | 
 |                                      sd_bus_message* msg, void* context, | 
 |                                      sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             int pgood = pwrObj->getPgood(); | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackGetPgood: {}", pgood).c_str()); | 
 |  | 
 |             sdbusplus::message_t(msg).append(pgood); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>("Unable to service get pgood property callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | int PowerInterface::callbackGetPgoodTimeout(sd_bus* /*bus*/, | 
 |                                             const char* /*path*/, | 
 |                                             const char* /*interface*/, | 
 |                                             const char* /*property*/, | 
 |                                             sd_bus_message* msg, void* context, | 
 |                                             sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             int timeout = pwrObj->getPgoodTimeout(); | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackGetPgoodTimeout: {}", timeout).c_str()); | 
 |  | 
 |             sdbusplus::message_t(msg).append(timeout); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>( | 
 |             "Unable to service get pgood timeout property callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | int PowerInterface::callbackGetPowerState(sd_bus_message* msg, void* context, | 
 |                                           sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             // Return the current power state of the GPIO, rather than the last | 
 |             // requested power state change | 
 |             int pgood = pwrObj->getPgood(); | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackGetPowerState: {}", pgood).c_str()); | 
 |  | 
 |             auto reply = sdbusplus::message_t(msg).new_method_return(); | 
 |             reply.append(pgood); | 
 |             reply.method_return(); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>("Unable to service getPowerState method callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | int PowerInterface::callbackSetPgoodTimeout(sd_bus* /*bus*/, | 
 |                                             const char* /*path*/, | 
 |                                             const char* /*interface*/, | 
 |                                             const char* /*property*/, | 
 |                                             sd_bus_message* msg, void* context, | 
 |                                             sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto m = sdbusplus::message_t(msg); | 
 |  | 
 |             int timeout{}; | 
 |             m.read(timeout); | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackSetPgoodTimeout: {}", timeout).c_str()); | 
 |  | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             pwrObj->setPgoodTimeout(timeout); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>( | 
 |             "Unable to service set pgood timeout property callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | int PowerInterface::callbackGetState(sd_bus* /*bus*/, const char* /*path*/, | 
 |                                      const char* /*interface*/, | 
 |                                      const char* /*property*/, | 
 |                                      sd_bus_message* msg, void* context, | 
 |                                      sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             int state = pwrObj->getState(); | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackGetState: {}", state).c_str()); | 
 |  | 
 |             sdbusplus::message_t(msg).append(state); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>("Unable to service get state property callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | int PowerInterface::callbackSetPowerState(sd_bus_message* msg, void* context, | 
 |                                           sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto m = sdbusplus::message_t(msg); | 
 |  | 
 |             int state{}; | 
 |             m.read(state); | 
 |  | 
 |             if (state != 1 && state != 0) | 
 |             { | 
 |                 return sd_bus_error_set(error, | 
 |                                         "org.openbmc.ControlPower.Error.Failed", | 
 |                                         "Invalid power state"); | 
 |             } | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackSetPowerState: {}", state).c_str()); | 
 |  | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             pwrObj->setState(state); | 
 |  | 
 |             m.new_method_return().method_return(); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>("Unable to service setPowerState method callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | int PowerInterface::callbackSetPowerSupplyError(sd_bus_message* msg, | 
 |                                                 void* context, | 
 |                                                 sd_bus_error* error) | 
 | { | 
 |     if (msg != nullptr && context != nullptr) | 
 |     { | 
 |         try | 
 |         { | 
 |             auto m = sdbusplus::message_t(msg); | 
 |  | 
 |             std::string psError{}; | 
 |             m.read(psError); | 
 |             log<level::INFO>( | 
 |                 fmt::format("callbackSetPowerSupplyError: {}", psError) | 
 |                     .c_str()); | 
 |  | 
 |             auto pwrObj = static_cast<PowerInterface*>(context); | 
 |             pwrObj->setPowerSupplyError(psError); | 
 |  | 
 |             m.new_method_return().method_return(); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             return sd_bus_error_set(error, e.name(), e.description()); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // The message or context were null | 
 |         log<level::ERR>( | 
 |             "Unable to service setPowerSupplyError method callback"); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 1; | 
 | } | 
 |  | 
 | void PowerInterface::emitPowerGoodSignal() | 
 | { | 
 |     log<level::INFO>("emitPowerGoodSignal"); | 
 |     serverInterface.new_signal("PowerGood").signal_send(); | 
 | } | 
 |  | 
 | void PowerInterface::emitPowerLostSignal() | 
 | { | 
 |     log<level::INFO>("emitPowerLostSignal"); | 
 |     serverInterface.new_signal("PowerLost").signal_send(); | 
 | } | 
 |  | 
 | void PowerInterface::emitPropertyChangedSignal(const char* property) | 
 | { | 
 |     log<level::INFO>( | 
 |         fmt::format("emitPropertyChangedSignal: {}", property).c_str()); | 
 |     serverInterface.property_changed(property); | 
 | } | 
 |  | 
 | const sdbusplus::vtable::vtable_t PowerInterface::vtable[] = { | 
 |     sdbusplus::vtable::start(), | 
 |     // Method setPowerState takes an int parameter and returns void | 
 |     sdbusplus::vtable::method("setPowerState", "i", "", callbackSetPowerState), | 
 |     // Method getPowerState takes no parameters and returns int | 
 |     sdbusplus::vtable::method("getPowerState", "", "i", callbackGetPowerState), | 
 |     // Signal PowerGood | 
 |     sdbusplus::vtable::signal("PowerGood", ""), | 
 |     // Signal PowerLost | 
 |     sdbusplus::vtable::signal("PowerLost", ""), | 
 |     // Property pgood is type int, read only, and uses the emits_change flag | 
 |     sdbusplus::vtable::property("pgood", "i", callbackGetPgood, | 
 |                                 sdbusplus::vtable::property_::emits_change), | 
 |     // Property state is type int, read only, and uses the emits_change flag | 
 |     sdbusplus::vtable::property("state", "i", callbackGetState, | 
 |                                 sdbusplus::vtable::property_::emits_change), | 
 |     // Property pgood_timeout is type int, read write, and uses the emits_change | 
 |     // flag | 
 |     sdbusplus::vtable::property("pgood_timeout", "i", callbackGetPgoodTimeout, | 
 |                                 callbackSetPgoodTimeout, | 
 |                                 sdbusplus::vtable::property_::emits_change), | 
 |     // Method setPowerSupplyError takes a string parameter and returns void | 
 |     sdbusplus::vtable::method("setPowerSupplyError", "s", "", | 
 |                               callbackSetPowerSupplyError), | 
 |     sdbusplus::vtable::end()}; | 
 |  | 
 | } // namespace phosphor::power::sequencer |