button-handler: Add ID button actions

Creates a signal handler for the 'Released' signal.

The handler will toggle the 'Asserted' property in the
LED group defined by the configure file.  The default
group is 'enclosure_identify'.  The effect of this is
the LEDs in the group will toggle on or off on each
button press.

Tested: Used the 'simPress' method on the ID button object.

Change-Id: I9f68a8b3fae02efc7f6cfb6dbcf8a45cce7f2d9c
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c4e8483..0fa7a58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,6 +14,7 @@
 set(LONG_PRESS_TIME_MS 3000)
 set(CHASSIS_STATE_OBJECT_NAME "xyz/openbmc_project/state/chassis")
 set(HOST_STATE_OBJECT_NAME "xyz/openbmc_project/state/host")
+set(ID_LED_GROUP "enclosure_identify" CACHE STRING "The identify LED group name")
 
 add_definitions(-DPOWER_DBUS_OBJECT_NAME="/${POWER_DBUS_OBJECT_NAME}0")
 add_definitions(-DRESET_DBUS_OBJECT_NAME="/${RESET_DBUS_OBJECT_NAME}0")
diff --git a/inc/button_handler.hpp b/inc/button_handler.hpp
index 0964aad..7340c2f 100644
--- a/inc/button_handler.hpp
+++ b/inc/button_handler.hpp
@@ -58,6 +58,15 @@
     void longPowerPressed(sdbusplus::message::message& msg);
 
     /**
+     * @brief The handler for an ID button press
+     *
+     * Toggles the ID LED group
+     *
+     * @param[in] msg - sdbusplus message from signal
+     */
+    void idPressed(sdbusplus::message::message& msg);
+
+    /**
      * @brief The handler for a reset button press
      *
      * Reboots the host if it is powered on.
@@ -101,6 +110,11 @@
     std::unique_ptr<sdbusplus::bus::match_t> powerButtonLongPressReleased;
 
     /**
+     * @brief Matches on the ID button released signal
+     */
+    std::unique_ptr<sdbusplus::bus::match_t> idButtonReleased;
+
+    /**
      * @brief Matches on the reset button released signal
      */
     std::unique_ptr<sdbusplus::bus::match_t> resetButtonReleased;
diff --git a/settings.hpp.in b/settings.hpp.in
index e89f312..f0ddd03 100644
--- a/settings.hpp.in
+++ b/settings.hpp.in
@@ -1,3 +1,4 @@
 #pragma once
 
 #cmakedefine LOOKUP_GPIO_BASE
+#cmakedefine ID_LED_GROUP "@ID_LED_GROUP@"
diff --git a/src/button_handler.cpp b/src/button_handler.cpp
index e31db4b..675f1ea 100644
--- a/src/button_handler.cpp
+++ b/src/button_handler.cpp
@@ -1,5 +1,7 @@
 #include "button_handler.hpp"
 
+#include "settings.hpp"
+
 #include <phosphor-logging/log.hpp>
 #include <xyz/openbmc_project/State/Chassis/server.hpp>
 #include <xyz/openbmc_project/State/Host/server.hpp>
@@ -18,11 +20,14 @@
 constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis";
 constexpr auto hostIface = "xyz.openbmc_project.State.Host";
 constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power";
+constexpr auto idButtonIface = "xyz.openbmc_project.Chassis.Buttons.ID";
 constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset";
 constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
+constexpr auto ledGroupIface = "xyz.openbmc_project.Led.Group";
 
 constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
+constexpr auto ledGroupBasePath = "/xyz/openbmc_project/led/groups/";
 
 Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus)
 {
@@ -57,6 +62,25 @@
 
     try
     {
+        if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty())
+        {
+            log<level::INFO>("Registering ID button handler");
+            idButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
+                bus,
+                sdbusRule::type::signal() + sdbusRule::member("Released") +
+                    sdbusRule::path(ID_DBUS_OBJECT_NAME) +
+                    sdbusRule::interface(idButtonIface),
+                std::bind(std::mem_fn(&Handler::idPressed), this,
+                          std::placeholders::_1));
+        }
+    }
+    catch (SdBusError& e)
+    {
+        // The button wasn't implemented
+    }
+
+    try
+    {
         if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
         {
             log<level::INFO>("Registering reset button handler");
@@ -194,5 +218,50 @@
                         entry("ERROR=%s", e.what()));
     }
 }
+
+void Handler::idPressed(sdbusplus::message::message& msg)
+{
+    std::string groupPath{ledGroupBasePath};
+    groupPath += ID_LED_GROUP;
+
+    auto service = getService(groupPath, ledGroupIface);
+
+    if (service.empty())
+    {
+        log<level::INFO>("No identify LED group found during ID button press",
+                         entry("GROUP=%s", groupPath.c_str()));
+        return;
+    }
+
+    try
+    {
+        auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
+                                          propertyIface, "Get");
+        method.append(ledGroupIface, "Asserted");
+        auto result = bus.call(method);
+
+        sdbusplus::message::variant<bool> state;
+        result.read(state);
+
+        state = !sdbusplus::message::variant_ns::get<bool>(state);
+
+        log<level::INFO>(
+            "Changing ID LED group state on ID LED press",
+            entry("GROUP=%s", groupPath.c_str()),
+            entry("STATE=%d",
+                  sdbusplus::message::variant_ns::get<bool>(state)));
+
+        method = bus.new_method_call(service.c_str(), groupPath.c_str(),
+                                     propertyIface, "Set");
+
+        method.append(ledGroupIface, "Asserted", state);
+        result = bus.call(method);
+    }
+    catch (SdBusError& e)
+    {
+        log<level::ERR>("Error toggling ID LED group on ID button press",
+                        entry("ERROR=%s", e.what()));
+    }
+}
 } // namespace button
 } // namespace phosphor