Add abstract factory to create button iface objects

A abstract factory class is implemented  to return
the instance of button interface class based on the
button iface formfactor name provided as
parameter to the abstract factory createInstance
 method.

Signed-off-by: Naveen Moses <naveen.mosess@hcl.com>
Change-Id: Ia791a2b6f52d09dd87da0e50a709fc72ac9d1bd7
diff --git a/src/gpio.cpp b/src/gpio.cpp
index 0538800..1caae54 100644
--- a/src/gpio.cpp
+++ b/src/gpio.cpp
@@ -83,14 +83,14 @@
     return getGpioBase() + offset;
 }
 
-int configGroupGpio(sdbusplus::bus::bus& bus, buttonConfig& buttonIFConfig)
+int configGroupGpio(buttonConfig& buttonIFConfig)
 {
     int result = 0;
     // iterate the list of gpios from the button interface config
     // and initialize them
     for (auto& gpioCfg : buttonIFConfig.gpios)
     {
-        result = configGpio(bus, gpioCfg);
+        result = configGpio(gpioCfg);
         if (result < 0)
         {
 
@@ -107,7 +107,7 @@
     return result;
 }
 
-int configGpio(sdbusplus::bus::bus& bus, gpioInfo& gpioConfig)
+int configGpio(gpioInfo& gpioConfig)
 {
 
     auto gpioNum = gpioConfig.number;
diff --git a/src/id_button.cpp b/src/id_button.cpp
index c543556..71e8539 100644
--- a/src/id_button.cpp
+++ b/src/id_button.cpp
@@ -16,7 +16,47 @@
 
 #include "id_button.hpp"
 
+// add the button iface class to registry
+static ButtonIFRegister<IDButton> buttonRegister;
+
 void IDButton::simPress()
 {
     pressed();
-}
\ No newline at end of file
+}
+
+void IDButton::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)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            (getFormFactorType() + " : lseek error!").c_str());
+        return;
+    }
+
+    n = ::read(fd, &buf, sizeof(buf));
+    if (n < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            (getFormFactorType() + " : read error!").c_str());
+        return;
+    }
+
+    if (buf == '0')
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            (getFormFactorType() + " : pressed").c_str());
+        // emit pressed signal
+        pressed();
+    }
+    else
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            (getFormFactorType() + " : released").c_str());
+        // released
+        released();
+    }
+}
diff --git a/src/main.cpp b/src/main.cpp
index ca7fbaa..a99c603 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -14,14 +14,12 @@
 // limitations under the License.
 */
 
+#include "button_factory.hpp"
 #include "gpio.hpp"
-#include "id_button.hpp"
-#include "power_button.hpp"
-#include "reset_button.hpp"
 
 #include <fstream>
 #include <nlohmann/json.hpp>
-
+#include <phosphor-logging/elog-errors.hpp>
 static constexpr auto gpioDefFile = "/etc/default/obmc/gpio/gpio_defs.json";
 
 int main(int argc, char* argv[])
@@ -29,7 +27,7 @@
     int ret = 0;
 
     phosphor::logging::log<phosphor::logging::level::INFO>(
-        "Start power button service...");
+        "Start Phosphor buttons service...");
 
     sd_event* event = nullptr;
     ret = sd_event_default(&event);
@@ -47,6 +45,8 @@
         bus, "/xyz/openbmc_project/Chassis/Buttons"};
 
     bus.request_name("xyz.openbmc_project.Chassis.Buttons");
+    //
+    std::vector<std::unique_ptr<ButtonIface>> buttonInterfaces;
 
     std::ifstream gpios{gpioDefFile};
     auto json = nlohmann::json::parse(gpios, nullptr, true);
@@ -54,9 +54,6 @@
 
     // load gpio config from gpio defs json file and create button interface
     // objects based on the button form factor type
-    std::unique_ptr<PowerButton> pb;
-    std::unique_ptr<ResetButton> rb;
-    std::unique_ptr<IDButton> ib;
 
     for (auto groupGpioConfig : gpioDefs)
     {
@@ -72,23 +69,9 @@
             buttonCfg.formFactorName = formFactorName;
             buttonCfg.gpios.push_back(gpioCfg);
         }
-        if (buttonCfg.formFactorName == PowerButton::getGpioName())
-        {
-            pb = std::make_unique<PowerButton>(bus, POWER_DBUS_OBJECT_NAME,
-                                               eventP, buttonCfg);
-        }
 
-        if (buttonCfg.formFactorName == ResetButton::getGpioName())
-        {
-            rb = std::make_unique<ResetButton>(bus, RESET_DBUS_OBJECT_NAME,
-                                               eventP, buttonCfg);
-        }
-
-        if (buttonCfg.formFactorName == IDButton::getGpioName())
-        {
-            ib = std::make_unique<IDButton>(bus, ID_DBUS_OBJECT_NAME, eventP,
-                                            buttonCfg);
-        }
+        buttonInterfaces.emplace_back(ButtonFactory::instance().createInstance(
+            formFactorName, bus, eventP, buttonCfg));
     }
 
     try
diff --git a/src/power_button.cpp b/src/power_button.cpp
index feadeee..2e69154 100644
--- a/src/power_button.cpp
+++ b/src/power_button.cpp
@@ -16,6 +16,9 @@
 
 #include "power_button.hpp"
 
+// add the button iface class to registry
+static ButtonIFRegister<PowerButton> buttonRegister;
+
 void PowerButton::simPress()
 {
     pressed();
@@ -25,3 +28,66 @@
 {
     pressedLong();
 }
+
+void PowerButton::updatePressedTime()
+{
+    pressedTime = std::chrono::steady_clock::now();
+}
+
+auto PowerButton::getPressTime() const
+{
+    return pressedTime;
+}
+
+void PowerButton::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)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "POWER_BUTTON: lseek error!");
+        return;
+    }
+
+    n = ::read(fd, &buf, sizeof(buf));
+    if (n < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "POWER_BUTTON: read error!");
+        return;
+    }
+
+    if (buf == '0')
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            "POWER_BUTTON: pressed");
+
+        updatePressedTime();
+        // emit pressed signal
+        pressed();
+    }
+    else
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            "POWER_BUTTON: released");
+
+        auto now = std::chrono::steady_clock::now();
+        auto d = std::chrono::duration_cast<std::chrono::milliseconds>(
+            now - getPressTime());
+
+        if (d > std::chrono::milliseconds(LONG_PRESS_TIME_MS))
+        {
+            pressedLong();
+        }
+        else
+        {
+            // released
+            released();
+        }
+    }
+}
diff --git a/src/reset_button.cpp b/src/reset_button.cpp
index 31e01e1..c3e467e 100644
--- a/src/reset_button.cpp
+++ b/src/reset_button.cpp
@@ -18,7 +18,51 @@
 
 #include "xyz/openbmc_project/Chassis/Buttons/Reset/server.hpp"
 
+// add the button iface class to registry
+static ButtonIFRegister<ResetButton> buttonRegister;
+
 void ResetButton::simPress()
 {
     pressed();
 }
+
+void ResetButton::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)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "RESET_BUTTON: lseek error!");
+
+        return;
+    }
+
+    n = ::read(fd, &buf, sizeof(buf));
+    if (n < 0)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "RESET_BUTTON: read error!");
+        return;
+    }
+
+    if (buf == '0')
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            "RESET_BUTTON: pressed");
+        // emit pressed signal
+        pressed();
+    }
+    else
+    {
+        phosphor::logging::log<phosphor::logging::level::DEBUG>(
+            "RESET_BUTTON: released");
+        // released
+        released();
+    }
+
+    return;
+}