Add support for tracking system power state
Change-Id: Ie0f27f696082ff3ee60c955992f3c2e55f4b5e57
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/power-supply/main.cpp b/power-supply/main.cpp
index af6bb9a..33729d8 100644
--- a/power-supply/main.cpp
+++ b/power-supply/main.cpp
@@ -56,16 +56,6 @@
return -4;
}
- auto bus = sdbusplus::bus::new_default();
-
- auto objname = "power_supply" + instnum;
- auto instance = std::stoul(instnum);
- auto psuDevice = std::make_unique<psu::PowerSupply>(objname,
- std::move(instance),
- std::move(objpath),
- std::move(invpath),
- bus);
-
sd_event* events = nullptr;
auto r = sd_event_default(&events);
@@ -76,17 +66,24 @@
return -5;
}
+ auto bus = sdbusplus::bus::new_default();
witherspoon::power::event::Event eventPtr{events};
//Attach the event object to the bus object so we can
//handle both sd_events (for the timers) and dbus signals.
bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
- //Attach the event object to the bus object so we can
- //handle both sd_events (for the timers) and dbus signals.
- bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
-
- // TODO: Get power state on startup.
+ auto objname = "power_supply" + instnum;
+ auto instance = std::stoul(instnum);
+ // The Witherspoon power supply can delay DC_GOOD active for 1 second.
+ std::chrono::seconds powerOnDelay(1);
+ auto psuDevice = std::make_unique<psu::PowerSupply>(objname,
+ std::move(instance),
+ std::move(objpath),
+ std::move(invpath),
+ bus,
+ eventPtr,
+ powerOnDelay);
auto pollInterval = std::chrono::milliseconds(1000);
DeviceMonitor mainloop(std::move(psuDevice), eventPtr, pollInterval);
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index 38eddf6..1510753 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -39,12 +39,21 @@
constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory";
constexpr auto INVENTORY_INTERFACE = "xyz.openbmc_project.Inventory.Item";
constexpr auto PRESENT_PROP = "Present";
+constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
+constexpr auto POWER_INTERFACE = "org.openbmc.control.Power";
PowerSupply::PowerSupply(const std::string& name, size_t inst,
- const std::string& objpath, const std::string& invpath,
- sdbusplus::bus::bus& bus)
- : Device(name, inst), monitorPath(objpath), inventoryPath(invpath),
- bus(bus), pmbusIntf(objpath)
+ const std::string& objpath,
+ const std::string& invpath,
+ sdbusplus::bus::bus& bus,
+ event::Event& e,
+ std::chrono::seconds& t)
+ : Device(name, inst), monitorPath(objpath), pmbusIntf(objpath),
+ inventoryPath(invpath), bus(bus), event(e), powerOnInterval(t),
+ powerOnTimer(e, [this]()
+ {
+ this->powerOn = true;
+ })
{
using namespace sdbusplus::bus;
auto present_obj_path = INVENTORY_OBJ_PATH + inventoryPath;
@@ -53,13 +62,26 @@
present_obj_path,
INVENTORY_INTERFACE),
[this](auto& msg)
- {
- this->inventoryChanged(msg);
- });
-
+ {
+ this->inventoryChanged(msg);
+ });
+ // Get initial presence state.
updatePresence();
+
+ // Subscribe to power state changes
+ powerOnMatch = std::make_unique<match_t>(bus,
+ match::rules::propertiesChanged(
+ POWER_OBJ_PATH,
+ POWER_INTERFACE),
+ [this](auto& msg)
+ {
+ this->powerStateChanged(msg);
+ });
+ // Get initial power state.
+ updatePowerState();
}
+
void PowerSupply::analyze()
{
using namespace witherspoon::pmbus;
@@ -196,6 +218,74 @@
}
+void PowerSupply::powerStateChanged(sdbusplus::message::message& msg)
+{
+ int32_t state = 0;
+ std::string msgSensor;
+ std::map<std::string, sdbusplus::message::variant<int32_t, int32_t>>
+ msgData;
+ msg.read(msgSensor, msgData);
+
+ // Check if it was the Present property that changed.
+ auto valPropMap = msgData.find("state");
+ if (valPropMap != msgData.end())
+ {
+ state = sdbusplus::message::variant_ns::get<int32_t>(valPropMap->second);
+
+ // Power is on when state=1. Set the fault logged variables to false
+ // and start the power on timer when the state changes to 1.
+ if (state)
+ {
+ readFailLogged = false;
+ vinUVFault = false;
+ inputFault = false;
+ powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot);
+ }
+ else
+ {
+ powerOnTimer.stop();
+ powerOn = false;
+ }
+ }
+
+}
+
+void PowerSupply::updatePowerState()
+{
+ // When state = 1, system is powered on
+ int32_t state = 0;
+
+ try
+ {
+ auto service = util::getService(POWER_OBJ_PATH,
+ POWER_INTERFACE,
+ bus);
+
+ // Use getProperty utility function to get power state.
+ util::getProperty<int32_t>(POWER_INTERFACE,
+ "state",
+ POWER_OBJ_PATH,
+ service,
+ bus,
+ state);
+
+ if (state)
+ {
+ powerOn = true;
+ }
+ else
+ {
+ powerOn = false;
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::INFO>("Failed to get power state. Assuming it is off.");
+ powerOn = false;
+ }
+
+}
+
void PowerSupply::clearFaults()
{
//TODO - Clear faults at pre-poweron. openbmc/openbmc#1736
diff --git a/power-supply/power_supply.hpp b/power-supply/power_supply.hpp
index 496218f..317c20b 100644
--- a/power-supply/power_supply.hpp
+++ b/power-supply/power_supply.hpp
@@ -2,6 +2,7 @@
#include <sdbusplus/bus/match.hpp>
#include "device.hpp"
#include "pmbus.hpp"
+#include "timer.hpp"
namespace witherspoon
{
@@ -34,11 +35,15 @@
* @param[in] objpath - the path to monitor
* @param[in] invpath - the inventory path to use
* @param[in] bus - D-Bus bus object
+ * @param[in] e - event object
+ * @param[in] t - time to allow power supply to assert PG#
*/
PowerSupply(const std::string& name, size_t inst,
const std::string& objpath,
const std::string& invpath,
- sdbusplus::bus::bus& bus);
+ sdbusplus::bus::bus& bus,
+ event::Event& e,
+ std::chrono::seconds& t);
/**
* Power supply specific function to analyze for faults/errors.
@@ -66,14 +71,6 @@
std::string monitorPath;
/**
- * The D-Bus path to use for this power supply's inventory status.
- */
- std::string inventoryPath;
-
- /** @brief Connection for sdbusplus bus */
- sdbusplus::bus::bus& bus;
-
- /**
* @brief Pointer to the PMBus interface
*
* Used to read out of or write to the /sysfs tree(s) containing files
@@ -83,13 +80,45 @@
witherspoon::pmbus::PMBus pmbusIntf;
/**
- * @brief True if the power supply is present.
+ * @brief D-Bus path to use for this power supply's inventory status.
*/
+ std::string inventoryPath;
+
+ /** @brief Connection for sdbusplus bus */
+ sdbusplus::bus::bus& bus;
+
+ /** @brief True if the power supply is present. */
bool present = false;
- /** @brief Used to subscribe to dbus pcap propety changes **/
+ /** @brief Used to subscribe to D-Bus property changes to Present **/
std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
+ /** @brief True if the power is on. */
+ bool powerOn = false;
+
+ /** @brief The sd_event structure used by the power on timer. */
+ event::Event& event;
+
+ /**
+ * @brief Interval to setting powerOn to true.
+ *
+ * The amount of time to wait from power state on to setting the
+ * internal powerOn state to true. The amount of time the power supply
+ * is allowed to delay setting DGood/PG#.
+ */
+ std::chrono::seconds powerOnInterval;
+
+ /**
+ * @brief Timer used to delay setting the internal powerOn state.
+ *
+ * The timer used to do the callback after the power state has been on
+ * long enough.
+ */
+ Timer powerOnTimer;
+
+ /** @brief Used to subscribe to D-Bus power on state changes **/
+ std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
+
/**
* @brief Has a PMBus read failure already been logged?
*/
@@ -128,6 +157,22 @@
* objects present member variable to reflect current status.
*/
void updatePresence();
+
+ /**
+ * @brief Updates the poweredOn status by querying D-Bus
+ *
+ * The D-Bus property for the sytem power state will be read to
+ * determine if the system is powered on or not.
+ */
+ void updatePowerState();
+
+ /** @brief Callback for power state property changes
+ * Process changes to the powered on stat property for the system.
+ *
+ * @param[in] msg - Data associated with the power state signal
+ */
+ void powerStateChanged(sdbusplus::message::message& msg);
+
};
}