blob: d266ee1ad64778ffcd58edd7eb2a44645e5d6f4e [file] [log] [blame]
/**
* 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::bus& 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::message(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::message(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::message(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::message(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::message(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::message(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::message(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