Add OCP debug card host selector button interface

A new button interface class definition is added for handling OCP
debug card host selector button events.
In case of the button release event, The host selector property is
 increased up to the max host position.

Design : https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/45544

Signed-off-by: Naveen Moses <naveen.mosess@hcl.com>
Change-Id: Iec8fabb00d1daa10f587981a9c77df8a62e3c373
diff --git a/src/button_handler.cpp b/src/button_handler.cpp
index 72d2f65..054f642 100644
--- a/src/button_handler.cpp
+++ b/src/button_handler.cpp
@@ -23,7 +23,7 @@
 constexpr auto hostSelectorIface =
     "xyz.openbmc_project.Chassis.Buttons.HostSelector";
 constexpr auto debugHostSelectorIface =
-    "xyz.openbmc_project.Chassis.Buttons.DebugHostSelector";
+    "xyz.openbmc_project.Chassis.Buttons.Button";
 
 constexpr auto propertyIface = "org.freedesktop.DBus.Properties";
 constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
@@ -98,6 +98,25 @@
     {
         // The button wasn't implemented
     }
+    try
+    {
+        if (!getService(DBG_HS_DBUS_OBJECT_NAME, debugHostSelectorIface)
+                 .empty())
+        {
+            lg2::info("Registering debug host selector button handler");
+            debugHSButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
+                bus,
+                sdbusRule::type::signal() + sdbusRule::member("Released") +
+                    sdbusRule::path(DBG_HS_DBUS_OBJECT_NAME) +
+                    sdbusRule::interface(debugHostSelectorIface),
+                std::bind(std::mem_fn(&Handler::debugHostSelectorReleased),
+                          this, std::placeholders::_1));
+        }
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        // The button wasn't implemented
+    }
 }
 bool Handler::isMultiHost()
 {
@@ -123,7 +142,7 @@
 
     if (HSService.empty())
     {
-        lg2::info("Host Selector dbus object not available");
+        lg2::info("Host selector dbus object not available");
         throw std::invalid_argument("Host selector dbus object not available");
     }
 
@@ -142,7 +161,7 @@
     }
     catch (const sdbusplus::exception_t& e)
     {
-        lg2::error("Error reading Host selector Position: {ERROR}", "ERROR", e);
+        lg2::error("Error reading host selector position: {ERROR}", "ERROR", e);
         throw;
     }
 }
@@ -175,7 +194,7 @@
     if (isMultiHostSystem)
     {
         hostNumber = getHostSelectorValue();
-        lg2::info("Multi host system detected : {POSITION}", "POSITION",
+        lg2::info("Multi-host system detected : {POSITION}", "POSITION",
                   hostNumber);
     }
 
@@ -183,10 +202,10 @@
 
     // ignore  power and reset button events if BMC is selected.
     if (isMultiHostSystem && (hostNumber == BMC_POSITION) &&
-        (powerEventType != PowerEvent::longPowerPressed))
+        (powerEventType != PowerEvent::longPowerReleased))
     {
         lg2::info(
-            "handlePowerEvent : BMC selected on multihost system. ignoring power and reset button events...");
+            "handlePowerEvent : BMC selected on multi-host system. ignoring power and reset button events...");
         return;
     }
 
@@ -204,11 +223,11 @@
             {
                 transition = Host::Transition::Off;
             }
-            lg2::info("handlePowerEvent : handle power button press ");
+            lg2::info("handlePowerEvent : Handle power button press ");
 
             break;
         }
-        case PowerEvent::longPowerPressed:
+        case PowerEvent::longPowerReleased:
         {
             dbusIfaceName = chassisIface;
             transitionName = "RequestedPowerTransition";
@@ -351,5 +370,60 @@
                    "ERROR", e);
     }
 }
+
+void Handler::increaseHostSelectorPosition()
+{
+    try
+    {
+        auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
+
+        if (HSService.empty())
+        {
+            lg2::error("Host selector service not available");
+            return;
+        }
+
+        auto method =
+            bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
+                                phosphor::button::propertyIface, "GetAll");
+        method.append(phosphor::button::hostSelectorIface);
+        auto result = bus.call(method);
+        std::unordered_map<std::string, std::variant<size_t>> properties;
+        result.read(properties);
+
+        auto maxPosition = std::get<size_t>(properties.at("MaxPosition"));
+        auto position = std::get<size_t>(properties.at("Position"));
+
+        std::variant<size_t> HSPositionVariant =
+            (position < maxPosition) ? (position + 1) : 0;
+
+        method = bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
+                                     phosphor::button::propertyIface, "Set");
+        method.append(phosphor::button::hostSelectorIface, "Position");
+
+        method.append(HSPositionVariant);
+        result = bus.call(method);
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        lg2::error("Error modifying host selector position : {ERROR}", "ERROR",
+                   e);
+    }
+}
+
+void Handler::debugHostSelectorReleased(sdbusplus::message::message& /* msg */)
+{
+    try
+    {
+        increaseHostSelectorPosition();
+    }
+    catch (const sdbusplus::exception::exception& e)
+    {
+        lg2::error(
+            "Failed power process debug host selector button press : {ERROR}",
+            "ERROR", e);
+    }
+}
+
 } // namespace button
 } // namespace phosphor
diff --git a/src/debugHostSelector_button.cpp b/src/debugHostSelector_button.cpp
new file mode 100644
index 0000000..6f078f2
--- /dev/null
+++ b/src/debugHostSelector_button.cpp
@@ -0,0 +1,66 @@
+#include "debugHostSelector_button.hpp"
+// add the button iface class to registry
+static ButtonIFRegister<DebugHostSelector> buttonRegister;
+using namespace phosphor::logging;
+
+void DebugHostSelector::simPress()
+{
+    pressed();
+}
+
+void DebugHostSelector::simRelease()
+{
+    released();
+}
+
+void DebugHostSelector::simLongPress()
+{
+    pressedLong();
+}
+
+/**
+ * @brief This method is called from sd-event provided callback function
+ * callbackHandler if platform specific event handling is needed then a
+ * derived class instance with its specific event handling logic along with
+ * init() function can be created to override the default event handling
+ */
+
+void DebugHostSelector::handleEvent(sd_event_source* /* es */, int fd,
+                                    uint32_t /* revents*/)
+{
+    int n = -1;
+    char buf = '0';
+
+    n = ::lseek(fd, 0, SEEK_SET);
+
+    if (n < 0)
+    {
+        lg2::error("GPIO fd lseek error!  : {FORM_FACTOR_TYPE}",
+                   "FORM_FACTOR_TYPE", getFormFactorType());
+        return;
+    }
+
+    n = ::read(fd, &buf, sizeof(buf));
+    if (n < 0)
+    {
+        lg2::error("GPIO fd read error!  : {FORM_FACTOR_TYPE}",
+                   "FORM_FACTOR_TYPE", getFormFactorType());
+        throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+            IOError();
+    }
+
+    if (buf == '0')
+    {
+        lg2::info("Button pressed : {FORM_FACTOR_TYPE}", "FORM_FACTOR_TYPE",
+                  getFormFactorType());
+        // emit pressed signal
+        pressed();
+    }
+    else
+    {
+        lg2::info("Button released{FORM_FACTOR_TYPE}", "FORM_FACTOR_TYPE",
+                  getFormFactorType());
+        // emit released signal
+        released();
+    }
+}
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 90c189d..16ae7b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,6 +19,7 @@
 
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/lg2.hpp>
 
 #include <fstream>
 static constexpr auto gpioDefFile = "/etc/default/obmc/gpio/gpio_defs.json";
@@ -29,15 +30,13 @@
 {
     int ret = 0;
 
-    phosphor::logging::log<phosphor::logging::level::INFO>(
-        "Start Phosphor buttons service...");
+    lg2::info("Start Phosphor buttons service...");
 
     sd_event* event = nullptr;
     ret = sd_event_default(&event);
     if (ret < 0)
     {
-        phosphor::logging::log<phosphor::logging::level::ERR>(
-            "Error creating a default sd_event handler");
+        lg2::error("Error creating a default sd_event handler");
         return ret;
     }
     EventPtr eventP{event};
@@ -68,6 +67,8 @@
         /* The folloing code checks if the gpio config read
         from json file is single gpio config or group gpio config,
         based on that further data is processed. */
+        lg2::debug("Found button config : {FORM_FACTOR_NAME}",
+                   "FORM_FACTOR_NAME", buttonCfg.formFactorName);
         if (gpioConfig.contains("group_gpio_config"))
         {
             const auto& groupGpio = gpioConfig["group_gpio_config"];
@@ -105,9 +106,8 @@
         ret = sd_event_loop(eventP.get());
         if (ret < 0)
         {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "Error occurred during the sd_event_loop",
-                phosphor::logging::entry("RET=%d", ret));
+            lg2::error("Error occurred during the sd_event_loop : {RESULT}",
+                       "RESULT", ret);
         }
     }
     catch (const std::exception& e)