Add Host selector button interface

This change includes new button interface
for the host selector switch.

The  button handler code is adapted to support
both single host and multiple host power control
dbus events.

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

Signed-off-by: Naveen Moses <naveen.mosess@hcl.com>
Change-Id: Icbfb22baaee057fd255c3ab0cba129693b913a9d
diff --git a/inc/button_handler.hpp b/inc/button_handler.hpp
index 7340c2f..b3c65f5 100644
--- a/inc/button_handler.hpp
+++ b/inc/button_handler.hpp
@@ -7,7 +7,12 @@
 {
 namespace button
 {
-
+enum class PowerEvent
+{
+    powerPressed,
+    longPowerPressed,
+    resetPressed
+};
 /**
  * @class Handler
  *
@@ -80,14 +85,9 @@
      *
      * @return true if powered on, false else
      */
-    bool poweredOn() const;
+    bool poweredOn(size_t hostNumber) const;
 
-    /**
-     * @brief Returns the service name for an object
-     *
-     * @param[in] path - the object path
-     * @param[in] interface - the interface name
-     *
+    /*
      * @return std::string - the D-Bus service name if found, else
      *                       an empty string
      */
@@ -95,6 +95,32 @@
                            const std::string& interface) const;
 
     /**
+     * @brief gets the valid host selector value in multi host
+     * system
+     *
+     * @return size_t throws exception if host selector position is
+     * invalid or not available.
+     */
+
+    size_t getHostSelectorValue();
+
+    /**
+     * @brief checks if the system has multi host
+     * based on the host selector property availability
+     *
+     * @return bool returns true if multi host system
+     * else returns false.
+     */
+    bool isMultiHost();
+    /**
+     * @brief trigger the power ctrl event based on the
+     *  button press event type.
+     *
+     * @return void
+     */
+    void handlePowerEvent(PowerEvent powerEventType);
+
+    /**
      * @brief sdbusplus connection object
      */
     sdbusplus::bus::bus& bus;
diff --git a/inc/button_interface.hpp b/inc/button_interface.hpp
index 8648797..f37a29c 100644
--- a/inc/button_interface.hpp
+++ b/inc/button_interface.hpp
@@ -50,8 +50,9 @@
 
             ButtonIface* buttonIface = static_cast<ButtonIface*>(userdata);
             buttonIface->handleEvent(es, fd, revents);
-            return 0;
         }
+
+        return 0;
     }
 
     std::string getFormFactorType() const
diff --git a/inc/gpio.hpp b/inc/gpio.hpp
index ebaf3cf..a5b943a 100644
--- a/inc/gpio.hpp
+++ b/inc/gpio.hpp
@@ -15,6 +15,7 @@
 */
 #pragma once
 
+#include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
 #include <string>
 #include <vector>
@@ -30,9 +31,9 @@
 // this struct represents button interface
 struct buttonConfig
 {
-    std::string formFactorName;  // name of the button interface
-    std::vector<gpioInfo> gpios; // holds single or group gpio config
-                                 // corresponding to button interface
+    std::string formFactorName;   // name of the button interface
+    std::vector<gpioInfo> gpios;  // holds single or group gpio config
+    nlohmann::json extraJsonInfo; // corresponding to button interface
 };
 
 /**
@@ -53,3 +54,5 @@
 
 uint32_t getGpioNum(const std::string& gpioPin);
 void closeGpio(int fd);
+// global json object which holds gpio_defs.json configs
+extern nlohmann::json gpioDefs;
diff --git a/inc/hostSelector_switch.hpp b/inc/hostSelector_switch.hpp
new file mode 100644
index 0000000..acdae19
--- /dev/null
+++ b/inc/hostSelector_switch.hpp
@@ -0,0 +1,76 @@
+#pragma once
+#include "button_factory.hpp"
+#include "button_interface.hpp"
+#include "common.hpp"
+#include "gpio.hpp"
+#include "xyz/openbmc_project/Chassis/Buttons/HostSelector/server.hpp"
+#include "xyz/openbmc_project/Chassis/Common/error.hpp"
+
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+
+static constexpr std::string_view HOST_SELECTOR = "HOST_SELECTOR";
+
+static constexpr auto INVALID_INDEX = std::numeric_limits<size_t>::max();
+
+enum class GpioState
+{
+    low,
+    high
+};
+
+class HostSelector final : public sdbusplus::server::object_t<
+                               sdbusplus::xyz::openbmc_project::Chassis::
+                                   Buttons::server::HostSelector>,
+                           public ButtonIface
+{
+  public:
+    HostSelector(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
+                 buttonConfig& buttonCfg) :
+        sdbusplus::server::object_t<sdbusplus::xyz::openbmc_project::Chassis::
+                                        Buttons::server::HostSelector>(
+            bus, path, action::defer_emit),
+        ButtonIface(bus, event, buttonCfg)
+    {
+        init();
+        // read and store the host selector position Map
+        hsPosMap = buttonCfg.extraJsonInfo.at("host_selector_map")
+                       .get<std::map<std::string, int>>();
+        maxPosition(buttonCfg.extraJsonInfo["max_position"], true);
+        gpioLineCount = buttonCfg.gpios.size();
+        setInitialHostSelectorValue();
+        emit_object_added();
+    }
+
+    ~HostSelector()
+    {
+        deInit();
+    }
+
+    static constexpr std::string_view getFormFactorName()
+    {
+        return HOST_SELECTOR;
+    }
+
+    static const char* getDbusObjectPath()
+    {
+        return HS_DBUS_OBJECT_NAME;
+    }
+    void handleEvent(sd_event_source* es, int fd, uint32_t revents) override;
+    size_t getMappedHSConfig(size_t hsPosition);
+    size_t getGpioIndex(int fd);
+    void setInitialHostSelectorValue(void);
+    void setHostSelectorValue(int fd, GpioState state);
+
+  protected:
+    size_t hostSelectorPosition = 0;
+    size_t gpioLineCount;
+
+    // map of read Host selector switch value and corresponding host number
+    // value.
+    std::map<std::string, int> hsPosMap;
+};