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/src/hostSelector_switch.cpp b/src/hostSelector_switch.cpp
new file mode 100644
index 0000000..c3ad83f
--- /dev/null
+++ b/src/hostSelector_switch.cpp
@@ -0,0 +1,133 @@
+
+#include "hostSelector_switch.hpp"
+
+// add the button iface class to registry
+static ButtonIFRegister<HostSelector> buttonRegister;
+using namespace phosphor::logging;
+size_t HostSelector::getMappedHSConfig(size_t hsPosition)
+{
+    size_t adjustedPosition = INVALID_INDEX; // set bmc as default value
+    std::string hsPosStr;
+    hsPosStr = std::to_string(hsPosition);
+
+    if (hsPosMap.find(hsPosStr) != hsPosMap.end())
+    {
+        adjustedPosition = hsPosMap[hsPosStr];
+    }
+    else
+    {
+        log<level::DEBUG>(
+            "getMappedHSConfig : no valid value in map.",
+            entry("FORM_FACTOR_TYPE=%s", (getFormFactorType()).c_str()));
+    }
+    return adjustedPosition;
+}
+
+size_t HostSelector::getGpioIndex(int fd)
+{
+    for (size_t index = 0; index < gpioLineCount; index++)
+    {
+        if (config.gpios[index].fd == fd)
+        {
+            return index;
+        }
+    }
+    return INVALID_INDEX;
+}
+void HostSelector::setInitialHostSelectorValue()
+{
+    char buf;
+    for (int index = 0; index < gpioLineCount; index++)
+    {
+        auto result = ::lseek(config.gpios[index].fd, 0, SEEK_SET);
+
+        if (result < 0)
+        {
+            log<level::ERR>(
+                "gpio fd lseek error!",
+                entry("FORM_FACTOR_TYPE=%s", (getFormFactorType()).c_str()));
+            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+                IOError();
+        }
+
+        result = ::read(config.gpios[index].fd, &buf, sizeof(buf));
+        if (result < 0)
+        {
+            log<level::ERR>(
+                "gpio fd read error!",
+                entry("FORM_FACTOR_TYPE=%s", (getFormFactorType()).c_str()));
+            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+                IOError();
+        }
+        GpioState gpioState =
+            (buf == '0') ? (GpioState::low) : (GpioState::high);
+        setHostSelectorValue(config.gpios[index].fd, gpioState);
+        size_t hsPosMapped = getMappedHSConfig(hostSelectorPosition);
+        if (hsPosMapped != INVALID_INDEX)
+        {
+            position(hsPosMapped, true);
+        }
+    }
+}
+
+void HostSelector::setHostSelectorValue(int fd, GpioState state)
+{
+    size_t pos = getGpioIndex(fd);
+
+    if (pos == INVALID_INDEX)
+    {
+        return;
+    }
+    auto set_bit = [](size_t& val, size_t n) { val |= 0xff & (1 << n); };
+
+    auto clr_bit = [](size_t& val, size_t n) { val &= ~(0xff & (1 << n)); };
+
+    auto bit_op = (state == GpioState::low) ? set_bit : clr_bit;
+
+    bit_op(hostSelectorPosition, pos);
+    return;
+}
+/**
+ * @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 HostSelector::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)
+    {
+        log<level::ERR>(
+            "gpio fd lseek error!",
+            entry("FORM_FACTOR_TYPE=%s", (getFormFactorType()).c_str()));
+        return;
+    }
+
+    n = ::read(fd, &buf, sizeof(buf));
+    if (n < 0)
+    {
+        log<level::ERR>(
+            "gpio fd read error!",
+            entry("FORM_FACTOR_TYPE=%s", (getFormFactorType()).c_str()));
+        throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+            IOError();
+    }
+
+    // read the gpio state for the io event received
+    GpioState gpioState = (buf == '0') ? (GpioState::low) : (GpioState::high);
+
+    setHostSelectorValue(fd, gpioState);
+
+    size_t hsPosMapped = getMappedHSConfig(hostSelectorPosition);
+
+    if (hsPosMapped != INVALID_INDEX)
+    {
+        position(hsPosMapped);
+    }
+}
\ No newline at end of file