From 11ca8f971526ded543c4b143af68973b520800a2 Mon Sep 17 00:00:00 2001 From: Vishwanatha Subbanna Date: Mon, 27 Feb 2017 19:33:45 +0530 Subject: Drive physical LED when a LED group is actioned on Change-Id: I3107c1d961c459379b77548a738533567eccf693 Signed-off-by: Vishwanatha Subbanna --- Makefile.am | 4 +-- configure.ac | 1 + led-main.cpp | 6 ++-- manager.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- manager.hpp | 79 +++++++++++++++++++++++++++++++++++++++++--- test/Makefile.am | 4 +-- test/utest.cpp | 38 +++++++++++----------- 7 files changed, 195 insertions(+), 36 deletions(-) diff --git a/Makefile.am b/Makefile.am index 921ec4c..228a810 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,7 @@ CLEANFILES = led-gen.hpp 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 @@ AS_IF([test "x$enable_oe_sdk" == "xyes"], # 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 #include #include +#include #include "manager.hpp" namespace phosphor { @@ -80,6 +81,13 @@ bool Manager::setGroupState(const std::string& path, bool assert, 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 @@ void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert, << 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 @@ void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert, 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 @@ void Manager::driveLEDs(group& ledsAssert, group& ledsDeAssert, 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({interface})); + + auto reply = bus.call(mapperCall); + if (reply.is_method_error()) + { + // Its okay if we do not see a corresponding physical LED. + log("Error looking up Physical LED service", + entry("PATH=%s",objPath.c_str())); + return ""; + } + + // Response by mapper in the case of success + std::map> serviceNames; + + // This is the service name for the passed in objpath + reply.read(serviceNames); + if (serviceNames.empty()) + { + log("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 #include +#include #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 @@ class Manager } using group = std::set; + using LedLayout = std::map; /** @brief static global map constructed at compile time */ - const std::map& 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& ledLayout) - : ledMap(ledLayout) + Manager(sdbusplus::bus::bus& bus, + const LedLayout& ledLayout) + : ledMap(ledLayout), + bus(bus) { // Nothing here } @@ -72,12 +82,71 @@ class Manager group& ledsUpdate); private: + /** @brief sdbusplus handler */ + sdbusplus::bus::bus& bus; + /** @brief Pointers to groups that are in asserted state */ std::set 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 + void drivePhysicalLED(const std::string& service, + const std::string& objPath, + const std::string& property, + const T& value) + { + sdbusplus::message::variant 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 @@ TESTS = $(check_PROGRAMS) # # 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 #include #include +#include #include "manager.hpp" #include "led-test-map.hpp" @@ -8,11 +9,12 @@ using namespace phosphor::led; 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 @@ class LedTest : public ::testing::Test /** @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 @@ TEST_F(LedTest, assertSingleLedOn) /** @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 @@ TEST_F(LedTest, assertSingleLedBlink) /** @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 @@ TEST_F(LedTest, assertSingleLedOnAndreAssert) /** @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 @@ TEST_F(LedTest, assertMultipleLedOn) /** @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 @@ TEST_F(LedTest, assertMultipleLedBlink) /** @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 @@ TEST_F(LedTest, assertMultipleLedBlinkAndDeAssert) /** @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 @@ TEST_F(LedTest, assertMultipleLedBlinkAndDeAssertTwice) /** @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 @@ TEST_F(LedTest, assertMultipleLedOnAndBlink) /** @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 @@ TEST_F(LedTest, assertTwoGroupsOnWithDistinctLEDOn) /** @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 @@ TEST_F(LedTest, asserttwoGroupsWithOneComonLEDOn) /** @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 @@ TEST_F(LedTest, assertTwoGroupsWithOneComonLEDInDifferentState) /** @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 @@ TEST_F(LedTest, assertTwoGroupsWithMultiplComonLEDOn) /** @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, assertTwoGroupsWithMultipleComonLEDInDifferentStates) */ TEST_F(LedTest, assertTwoGroupsWithMultipleComonLEDAndDeAssertOne) { - Manager manager(twoGroupsWithMultiplComonLEDOn); + Manager manager(bus, twoGroupsWithMultiplComonLEDOn); { // Assert Set-A Manager::group ledsAssert {}; @@ -775,7 +777,7 @@ TEST_F(LedTest, assertTwoGroupsWithMultipleComonLEDAndDeAssertOne) * different state and De-Assert one*/ TEST_F(LedTest, assertTwoGroupsWithMultipleComonLEDInDifferentStateDeAssertOne) { - Manager manager(twoGroupsWithMultipleComonLEDInDifferentState); + Manager manager(bus, twoGroupsWithMultipleComonLEDInDifferentState); { // Assert Set-B Manager::group ledsAssert {}; -- cgit v1.2.1