Drive physical LED when a LED group is actioned on
Change-Id: I3107c1d961c459379b77548a738533567eccf693
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 921ec4c..228a810 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@
led-gen.hpp: ${srcdir}/parse_led.py
$(AM_V)@LEDGEN@ > $@
-phosphor_ledmanager_LDFLAGS = $(SYSTEMD_LIBS)
-phosphor_ledmanager_CFLAGS = $(SYSTEMD_CFLAGS)
+phosphor_ledmanager_LDFLAGS = $(SYSTEMD_LIBS) $(SDBUSPLUS_LIBS) $(PHOSPHOR_LOGGING_LIBS)
+phosphor_ledmanager_CFLAGS = $(SYSTEMD_CFLAGS) $(SDBUSPLUS_CFLAGS) $(PHOSPHOR_LOGGING_CFLAGS)
SUBDIRS = test
diff --git a/configure.ac b/configure.ac
index 0286aa6..83c45bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,7 @@
# Checks for header files.
AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd developement package required])])
AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])])
+PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],, [AC_MSG_ERROR([Could not find phosphor-logging...openbmc/phosphor-logging package required])])
# Dbus service name
AC_ARG_VAR(BUSNAME, [The Dbus busname to own])
diff --git a/led-main.cpp b/led-main.cpp
index 2dc0dce..4df1a6a 100644
--- a/led-main.cpp
+++ b/led-main.cpp
@@ -7,12 +7,12 @@
int main(void)
{
- /** @brief Group manager object */
- phosphor::led::Manager manager(systemLedMap);
-
/** @brief Dbus constructs used by LED Group manager */
sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
+ /** @brief Group manager object */
+ phosphor::led::Manager manager(bus, systemLedMap);
+
/** @brief sd_bus object manager */
sdbusplus::server::manager::manager objManager(bus, OBJPATH);
diff --git a/manager.cpp b/manager.cpp
index e4137d3..44b0480 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -1,6 +1,7 @@
#include <iostream>
#include <string>
#include <algorithm>
+#include <phosphor-logging/log.hpp>
#include "manager.hpp"
namespace phosphor
{
@@ -80,6 +81,13 @@
void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert,
group& ledsUpdate)
{
+ // For now, physical LED is driven by xyz.openbmc_project.Led.Controller
+ // at /xyz/openbmc_project/led/physical. However, its possible that in the
+ // future, the physical LEDs are driven by different dbus services.
+ // when that happens, service name needs to be obtained everytime a
+ // particular LED would be targeted as opposed to getting one now and then
+ // using it for all
+
// This order of LED operation is important.
if (ledsUpdate.size())
{
@@ -87,8 +95,8 @@
<< std::endl;
for (const auto& it: ledsUpdate)
{
- std::cout << "\t{" << it.name << "::" << it.action << "}"
- << std::endl;
+ std::string objPath = std::string(PHY_LED_PATH) + it.name;
+ drivePhysicalLED(objPath, it.action, it.dutyOn);
}
}
@@ -97,8 +105,8 @@
std::cout << "De-Asserting LEDs" << std::endl;
for (const auto& it: ledsDeAssert)
{
- std::cout << "\t{" << it.name << "::" << it.action << "}"
- << std::endl;
+ std::string objPath = std::string(PHY_LED_PATH) + it.name;
+ drivePhysicalLED(objPath, Layout::Action::Off, it.dutyOn);
}
}
@@ -107,12 +115,91 @@
std::cout << "Asserting LEDs" << std::endl;
for (const auto& it: ledsAssert)
{
- std::cout << "\t{" << it.name << "::" << it.action << "}"
- << std::endl;
+ std::string objPath = std::string(PHY_LED_PATH) + it.name;
+ drivePhysicalLED(objPath, it.action, it.dutyOn);
}
}
return;
}
+// Calls into driving physical LED post choosing the action
+void Manager::drivePhysicalLED(const std::string& objPath,
+ Layout::Action action,
+ uint8_t dutyOn)
+{
+ auto service = getServiceName(objPath, PHY_LED_IFACE);
+ if (!service.empty())
+ {
+ // If Blink, set its property
+ if (action == Layout::Action::Blink)
+ {
+ drivePhysicalLED(service, objPath, "DutyOn", dutyOn);
+ }
+ drivePhysicalLED(service, objPath, "State",
+ getPhysicalAction(action));
+ }
+}
+
+/** @brief Returns action string based on enum */
+const char* const Manager::getPhysicalAction(Layout::Action action)
+{
+ // TODO : When this is moved over to using libdus interfaces, this code will
+ // away. https://github.com/openbmc/phosphor-led-manager/issues/2
+ if(action == Layout::Action::On)
+ {
+ return "xyz.openbmc_project.Led.Physical.Action.On";
+ }
+ else if(action == Layout::Action::Blink)
+ {
+ return "xyz.openbmc_project.Led.Physical.Action.Blink";
+ }
+ else
+ {
+ return "xyz.openbmc_project.Led.Physical.Action.Off";
+ }
+}
+
+/** Given the LED dbus path and interface, returns the service name */
+std::string Manager::getServiceName(const std::string& objPath,
+ const std::string& interface) const
+{
+ using namespace phosphor::logging;
+
+ // Mapper dbus constructs
+ constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+ constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/ObjectMapper";
+ constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
+
+ // Make a mapper call
+ auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
+ MAPPER_IFACE, "GetObject");
+ // Cook rest of the things.
+ mapperCall.append(objPath);
+ mapperCall.append(std::vector<std::string>({interface}));
+
+ auto reply = bus.call(mapperCall);
+ if (reply.is_method_error())
+ {
+ // Its okay if we do not see a corresponding physical LED.
+ log<level::INFO>("Error looking up Physical LED service",
+ entry("PATH=%s",objPath.c_str()));
+ return "";
+ }
+
+ // Response by mapper in the case of success
+ std::map<std::string, std::vector<std::string>> serviceNames;
+
+ // This is the service name for the passed in objpath
+ reply.read(serviceNames);
+ if (serviceNames.empty())
+ {
+ log<level::INFO>("Physical LED lookup did not return any service",
+ entry("PATH=%s",objPath.c_str()));
+ return "";
+ }
+
+ return serviceNames.begin()->first;
+}
+
} // namespace led
} // namespace phosphor
diff --git a/manager.hpp b/manager.hpp
index 10af42d..8dbbcd6 100644
--- a/manager.hpp
+++ b/manager.hpp
@@ -2,12 +2,18 @@
#include <map>
#include <set>
+#include <sdbusplus/bus.hpp>
#include "ledlayout.hpp"
namespace phosphor
{
namespace led
{
+/** @brief Physical LED dbus constructs */
+constexpr auto PHY_LED_PATH = "/xyz/openbmc_project/led/physical/";
+constexpr auto PHY_LED_IFACE = "xyz.openbmc_project.Led.Physical";
+constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
+
/** @class Manager
* @brief Manages group of LEDs and applies action on the elements of group
*/
@@ -30,16 +36,20 @@
}
using group = std::set<phosphor::led::Layout::LedAction>;
+ using LedLayout = std::map<std::string, group>;
/** @brief static global map constructed at compile time */
- const std::map<std::string, group>& ledMap;
+ const LedLayout& ledMap;
- /** @brief Refer the user supplied LED layout.
+ /** @brief Refer the user supplied LED layout and sdbusplus handler
*
- * @param [in] ledLayout - LEDs group layout
+ * @param [in] bus - sdbusplus handler
+ * @param [in] LedLayout - LEDs group layout
*/
- explicit Manager(const std::map<std::string, Manager::group>& ledLayout)
- : ledMap(ledLayout)
+ Manager(sdbusplus::bus::bus& bus,
+ const LedLayout& ledLayout)
+ : ledMap(ledLayout),
+ bus(bus)
{
// Nothing here
}
@@ -72,12 +82,71 @@
group& ledsUpdate);
private:
+ /** @brief sdbusplus handler */
+ sdbusplus::bus::bus& bus;
+
/** @brief Pointers to groups that are in asserted state */
std::set<const group*> assertedGroups;
/** @brief Contains the LEDs that are in asserted state */
group currentState;
+ /** @brief Returns action string based on enum
+ *
+ * @param[in] action - Action enum
+ *
+ * @return string equivalent of the passed in enumeration
+ */
+ static const char* const getPhysicalAction(Layout::Action action);
+
+ /** @brief Chooses appropriate action to be triggered on physical LED
+ * and calls into function that applies the actual action.
+ *
+ * @param[in] objPath - dbus object path
+ * @param[in] action - Intended action to be triggered
+ * @param[in] dutyOn - Duty Cycle ON percentage
+ */
+ void drivePhysicalLED(const std::string& objPath,
+ Layout::Action action,
+ uint8_t dutyOn);
+
+ /** @brief Makes a dbus call to a passed in service name.
+ * This is now the physical LED controller
+ *
+ * @param[in] service - dbus service name
+ * @param[in] objPath - dbus object path
+ * @param[in] property - property to be written to
+ * @param[in] value - Value to write
+ */
+ template <typename T>
+ void drivePhysicalLED(const std::string& service,
+ const std::string& objPath,
+ const std::string& property,
+ const T& value)
+ {
+ sdbusplus::message::variant<T> data = value;
+
+ auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
+ DBUS_PROPERTY_IFACE, "Set");
+ method.append(PHY_LED_IFACE);
+ method.append(property);
+ method.append(data);
+
+ // There will be exceptions going forward and hence don't need a
+ // response
+ bus.call_noreply(method);
+ return;
+ }
+
+ /** @brief Finds the service name given a dbus object path and interface
+ *
+ * @param[in] objPath - dbus object path
+ * @param[in] interface - dbus interface
+ *
+ * @return: Service name or none
+ */
+ std::string getServiceName(const std::string& objPath,
+ const std::string& interface) const;
};
} // namespace led
diff --git a/test/Makefile.am b/test/Makefile.am
index e434c40..6efd2c7 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -5,8 +5,8 @@
# # Build/add utest to test suite
check_PROGRAMS = utest
-utest_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS)
+utest_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS) $(PHOSPHOR_LOGGING_CFLAGS)
utest_CXXFLAGS = $(PTHREAD_CFLAGS)
-utest_LDFLAGS = -lgtest_main -lgtest $(PTHREAD_LIBS) $(OESDK_TESTCASE_FLAGS)
+utest_LDFLAGS = -lgtest_main -lgtest $(PTHREAD_LIBS) $(OESDK_TESTCASE_FLAGS) $(SYSTEMD_LIBS) $(PHOSPHOR_LOGGING_LIBS)
utest_SOURCES = utest.cpp
utest_LDADD = $(top_builddir)/manager.o
diff --git a/test/utest.cpp b/test/utest.cpp
index 38f8196..7450f09 100644
--- a/test/utest.cpp
+++ b/test/utest.cpp
@@ -1,6 +1,7 @@
#include <set>
#include <algorithm>
#include <gtest/gtest.h>
+#include <sdbusplus/bus.hpp>
#include "manager.hpp"
#include "led-test-map.hpp"
@@ -8,11 +9,12 @@
class LedTest : public ::testing::Test
{
public:
- virtual void SetUp()
+ sdbusplus::bus::bus bus;
+ LedTest() : bus(sdbusplus::bus::new_default())
{
- // Not having a need at the moment but for future.
+ // Nothing here
}
- virtual void TearDown()
+ ~LedTest()
{
// Leaving upto auto cleanup.
}
@@ -21,7 +23,7 @@
/** @brief Assert Single LED to On */
TEST_F(LedTest, assertSingleLedOn)
{
- Manager manager(singleLedOn);
+ Manager manager(bus, singleLedOn);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -53,7 +55,7 @@
/** @brief Assert Single LED to Blink */
TEST_F(LedTest, assertSingleLedBlink)
{
- Manager manager(singleLedBlink);
+ Manager manager(bus, singleLedBlink);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -85,7 +87,7 @@
/** @brief Assert Single LED to On and Try Assert Again */
TEST_F(LedTest, assertSingleLedOnAndreAssert)
{
- Manager manager(singleLedOn);
+ Manager manager(bus, singleLedOn);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -132,7 +134,7 @@
/** @brief Assert Multiple LEDs to On */
TEST_F(LedTest, assertMultipleLedOn)
{
- Manager manager(multipleLedsOn);
+ Manager manager(bus, multipleLedsOn);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -166,7 +168,7 @@
/** @brief Assert Multiple LEDs to Blink */
TEST_F(LedTest, assertMultipleLedBlink)
{
- Manager manager(multipleLedsBlink);
+ Manager manager(bus, multipleLedsBlink);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -200,7 +202,7 @@
/** @brief Assert Multiple LEDs to Blink, DeAssert */
TEST_F(LedTest, assertMultipleLedBlinkAndDeAssert)
{
- Manager manager(multipleLedsBlink);
+ Manager manager(bus, multipleLedsBlink);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -262,7 +264,7 @@
/** @brief Assert Multiple LEDs to Blink, DeAssert Twice */
TEST_F(LedTest, assertMultipleLedBlinkAndDeAssertTwice)
{
- Manager manager(multipleLedsBlink);
+ Manager manager(bus, multipleLedsBlink);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -338,7 +340,7 @@
/** @brief Assert Multiple LEDs to mix of On and Blink */
TEST_F(LedTest, assertMultipleLedOnAndBlink)
{
- Manager manager(multipleLedsOnAndBlink);
+ Manager manager(bus, multipleLedsOnAndBlink);
{
// Assert the LEDs.
Manager::group ledsAssert {};
@@ -374,7 +376,7 @@
/** @brief Assert 2 groups having distinct LEDs */
TEST_F(LedTest, assertTwoGroupsOnWithDistinctLEDOn)
{
- Manager manager(twoGroupsWithDistinctLEDsOn);
+ Manager manager(bus, twoGroupsWithDistinctLEDsOn);
{
// Assert Set-A
Manager::group ledsAssert {};
@@ -436,7 +438,7 @@
/** @brief Assert 2 groups having one of the LEDs common */
TEST_F(LedTest, asserttwoGroupsWithOneComonLEDOn)
{
- Manager manager(twoGroupsWithOneComonLEDOn);
+ Manager manager(bus, twoGroupsWithOneComonLEDOn);
{
// Assert Set-A
Manager::group ledsAssert {};
@@ -497,7 +499,7 @@
/** @brief Assert 2 groups having one of the LEDs common in different state */
TEST_F(LedTest, assertTwoGroupsWithOneComonLEDInDifferentState)
{
- Manager manager(twoGroupsWithOneComonLEDInDifferentState);
+ Manager manager(bus, twoGroupsWithOneComonLEDInDifferentState);
{
// Assert Set-A
Manager::group ledsAssert {};
@@ -560,7 +562,7 @@
/** @brief Assert 2 groups having multiple common LEDs in Same State */
TEST_F(LedTest, assertTwoGroupsWithMultiplComonLEDOn)
{
- Manager manager(twoGroupsWithMultiplComonLEDOn);
+ Manager manager(bus, twoGroupsWithMultiplComonLEDOn);
{
// Assert Set-B
Manager::group ledsAssert {};
@@ -621,7 +623,7 @@
/** @brief Assert 2 groups having multiple LEDs common in different state */
TEST_F(LedTest, assertTwoGroupsWithMultipleComonLEDInDifferentStates)
{
- Manager manager(twoGroupsWithMultipleComonLEDInDifferentState);
+ Manager manager(bus, twoGroupsWithMultipleComonLEDInDifferentState);
{
// Assert Set-A
Manager::group ledsAssert {};
@@ -687,7 +689,7 @@
*/
TEST_F(LedTest, assertTwoGroupsWithMultipleComonLEDAndDeAssertOne)
{
- Manager manager(twoGroupsWithMultiplComonLEDOn);
+ Manager manager(bus, twoGroupsWithMultiplComonLEDOn);
{
// Assert Set-A
Manager::group ledsAssert {};
@@ -775,7 +777,7 @@
* different state and De-Assert one*/
TEST_F(LedTest, assertTwoGroupsWithMultipleComonLEDInDifferentStateDeAssertOne)
{
- Manager manager(twoGroupsWithMultipleComonLEDInDifferentState);
+ Manager manager(bus, twoGroupsWithMultipleComonLEDInDifferentState);
{
// Assert Set-B
Manager::group ledsAssert {};