psu-ng: Add method to get PSU conf from D-Bus.
Add a getPSUProperties method that will get the power supply unit
configuration information from the D-Bus properties populated by
entity-manager. The IBM common form factor power supplies will have
these properties under the interface called
xyz.openbmc_project.Configuration.IBMCFFPSConnector. See
I45b724238cffe6fb7f1f8f9947fa1c2c9e9e8015 for changes to add the
necessary updates to entity-manager.
The D-Bus property for I2CAddress is a uint64_t type, while the JSON
configuration file had a string. Move the PowerSupply constructor to the
cpp file, updated to take in uint16_t for the i2caddr.
Update PSUManager::getJSONProperties() to convert Address from string to
uint16_t.
Add in a PSUManager constructor to use the getPSUProperties() function.
Add code to handle interfacesAdded from entity-manager prior to
getPSUProperties() or getSystemProperties().
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
Change-Id: I553e8982cf008828823cea2c0f017ff23c9070ab
diff --git a/phosphor-power-supply/psu_manager.cpp b/phosphor-power-supply/psu_manager.cpp
index fa1294a..5bb0807 100644
--- a/phosphor-power-supply/psu_manager.cpp
+++ b/phosphor-power-supply/psu_manager.cpp
@@ -11,6 +11,12 @@
namespace phosphor::power::manager
{
+constexpr auto IBMCFFPSInterface =
+ "xyz.openbmc_project.Configuration.IBMCFFPSConnector";
+constexpr auto i2cBusProp = "I2CBus";
+constexpr auto i2cAddressProp = "I2CAddress";
+constexpr auto psuNameProp = "Name";
+
constexpr auto supportedConfIntf =
"xyz.openbmc_project.Configuration.SupportedConfiguration";
constexpr auto maxCountProp = "MaxCount";
@@ -19,8 +25,8 @@
const std::string& configfile) :
bus(bus)
{
- // Parse out the JSON properties
sysProperties = {0};
+ // Parse out the JSON properties
getJSONProperties(configfile);
// Subscribe to InterfacesAdded before doing a property read, otherwise
// the interface could be created after the read attempt but before the
@@ -50,6 +56,39 @@
initialize();
}
+PSUManager::PSUManager(sdbusplus::bus::bus& bus, const sdeventplus::Event& e) :
+ bus(bus)
+{
+ sysProperties = {0};
+ // Subscribe to InterfacesAdded before doing a property read, otherwise
+ // the interface could be created after the read attempt but before the
+ // match is created.
+ entityManagerIfacesAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusplus::bus::match::rules::interfacesAdded() +
+ sdbusplus::bus::match::rules::sender(
+ "xyz.openbmc_project.EntityManager"),
+ std::bind(&PSUManager::entityManagerIfaceAdded, this,
+ std::placeholders::_1));
+ getPSUConfiguration();
+ getSystemProperties();
+
+ using namespace sdeventplus;
+ auto interval = std::chrono::milliseconds(1000);
+ timer = std::make_unique<utility::Timer<ClockId::Monotonic>>(
+ e, std::bind(&PSUManager::analyze, this), interval);
+
+ // Subscribe to power state changes
+ powerService = util::getService(POWER_OBJ_PATH, POWER_IFACE, bus);
+ powerOnMatch = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH,
+ POWER_IFACE),
+ [this](auto& msg) { this->powerStateChanged(msg); });
+
+ initialize();
+}
+
void PSUManager::getJSONProperties(const std::string& path)
{
nlohmann::json configFileJSON = util::loadJSONFromFile(path.c_str());
@@ -71,7 +110,7 @@
{
std::string invpath = psuJSON["Inventory"];
std::uint8_t i2cbus = psuJSON["Bus"];
- std::string i2caddr = psuJSON["Address"];
+ std::uint16_t i2caddr = static_cast<uint16_t>(psuJSON["Address"]);
auto psu =
std::make_unique<PowerSupply>(bus, invpath, i2cbus, i2caddr);
psus.emplace_back(std::move(psu));
@@ -88,6 +127,93 @@
}
}
+void PSUManager::getPSUConfiguration()
+{
+ using namespace phosphor::power::util;
+ auto depth = 0;
+ auto objects = getSubTree(bus, "/", IBMCFFPSInterface, depth);
+
+ psus.clear();
+
+ // I should get a map of objects back.
+ // Each object will have a path, a service, and an interface.
+ // The interface should match the one passed into this function.
+ for (const auto& [path, services] : objects)
+ {
+ auto service = services.begin()->first;
+
+ if (path.empty() || service.empty())
+ {
+ continue;
+ }
+
+ // For each object in the array of objects, I want to get properties
+ // from the service, path, and interface.
+ auto properties =
+ getAllProperties(bus, path, IBMCFFPSInterface, service);
+
+ getPSUProperties(properties);
+ }
+
+ if (psus.empty())
+ {
+ // Interface or properties not found. Let the Interfaces Added callback
+ // process the information once the interfaces are added to D-Bus.
+ log<level::INFO>(fmt::format("No power supplies to monitor").c_str());
+ }
+}
+
+void PSUManager::getPSUProperties(util::DbusPropertyMap& properties)
+{
+ // From passed in properties, I want to get: I2CBus, I2CAddress,
+ // and Name. Create a power supply object, using Name to build the inventory
+ // path.
+ const auto basePSUInvPath =
+ "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply";
+ uint64_t* i2cbus = nullptr;
+ uint64_t* i2caddr = nullptr;
+ std::string* psuname = nullptr;
+
+ for (const auto& property : properties)
+ {
+ try
+ {
+ if (property.first == i2cBusProp)
+ {
+ i2cbus = std::get_if<uint64_t>(&properties[i2cBusProp]);
+ }
+ else if (property.first == i2cAddressProp)
+ {
+ i2caddr = std::get_if<uint64_t>(&properties[i2cAddressProp]);
+ }
+ else if (property.first == psuNameProp)
+ {
+ psuname = std::get_if<std::string>(&properties[psuNameProp]);
+ }
+ }
+ catch (std::exception& e)
+ {
+ }
+ }
+
+ if ((i2cbus) && (i2caddr) && (psuname) && (!psuname->empty()))
+ {
+ std::string invpath = basePSUInvPath;
+ invpath.push_back(psuname->back());
+
+ log<level::DEBUG>(fmt::format("Inventory Path: {}", invpath).c_str());
+
+ auto psu =
+ std::make_unique<PowerSupply>(bus, invpath, *i2cbus, *i2caddr);
+ psus.emplace_back(std::move(psu));
+ }
+
+ if (psus.empty())
+ {
+ log<level::INFO>(fmt::format("No power supplies to monitor").c_str());
+ }
+}
+
void PSUManager::populateSysProperties(const util::DbusPropertyMap& properties)
{
try
@@ -148,12 +274,19 @@
msg.read(objPath, interfaces);
auto itIntf = interfaces.find(supportedConfIntf);
- if (itIntf == interfaces.cend())
+ if (itIntf != interfaces.cend())
{
- return;
+ populateSysProperties(itIntf->second);
}
- populateSysProperties(itIntf->second);
+ itIntf = interfaces.find(IBMCFFPSInterface);
+ if (itIntf != interfaces.cend())
+ {
+ log<level::INFO>(
+ fmt::format("InterfacesAdded for: {}", IBMCFFPSInterface)
+ .c_str());
+ getPSUProperties(itIntf->second);
+ }
}
catch (std::exception& e)
{