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/inc/button_factory.hpp b/inc/button_factory.hpp
new file mode 100644
index 0000000..81c8e47
--- /dev/null
+++ b/inc/button_factory.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "button_interface.hpp"
+#include "gpio.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <unordered_map>
+
+using buttonIfCreatorMethod = std::function<std::unique_ptr<ButtonIface>(
+    sdbusplus::bus::bus& bus, EventPtr& event, buttonConfig& buttonCfg)>;
+
+/**
+ * @brief This is abstract factory for the creating phosphor buttons objects
+ * based on the button  / formfactor type given.
+ */
+
+class ButtonFactory
+{
+
+  public:
+    static ButtonFactory& instance()
+    {
+        static ButtonFactory buttonFactoryObj;
+        return buttonFactoryObj;
+    }
+
+    /**
+     * @brief this method creates a key and value pair element
+     * for the given button interface where key is the form factor
+     * name and the value is lambda method to return
+     * the instance of the button interface.
+     * This key value pair is stored in the Map buttonIfaceRegistry.
+     */
+
+    template <typename T>
+    void addToRegistry()
+    {
+
+        buttonIfaceRegistry[std::string(T::getFormFactorName())] =
+            [](sdbusplus::bus::bus& bus, EventPtr& event,
+               buttonConfig& buttonCfg) {
+                return std::make_unique<T>(bus, T::getDbusObjectPath(), event,
+                                           buttonCfg);
+            };
+    }
+    /**
+     * @brief this method returns the button interface object
+     *    corresponding to the button formfactor name provided
+     */
+    std::unique_ptr<ButtonIface> createInstance(std::string name,
+                                                sdbusplus::bus::bus& bus,
+                                                EventPtr& event,
+                                                buttonConfig& buttonCfg)
+    {
+
+        // find matching name in the registry and call factory method.
+
+        return buttonIfaceRegistry.at(name)(bus, event, buttonCfg);
+    }
+
+  private:
+    // This map is the registry for keeping supported button interface types.
+    std::unordered_map<std::string, buttonIfCreatorMethod> buttonIfaceRegistry;
+};
+
+template <class T>
+class ButtonIFRegister
+{
+  public:
+    ButtonIFRegister()
+    {
+        // register the class factory function
+        ButtonFactory::instance().addToRegistry<T>();
+    }
+};
\ No newline at end of file
diff --git a/inc/button_interface.hpp b/inc/button_interface.hpp
new file mode 100644
index 0000000..8648797
--- /dev/null
+++ b/inc/button_interface.hpp
@@ -0,0 +1,118 @@
+#pragma once
+
+#include "common.hpp"
+#include "gpio.hpp"
+#include "xyz/openbmc_project/Chassis/Common/error.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+// This is the base class for all the button interface types
+//
+class ButtonIface
+{
+
+  public:
+    ButtonIface(sdbusplus::bus::bus& bus, EventPtr& event,
+                buttonConfig& buttonCfg,
+                sd_event_io_handler_t handler = ButtonIface::EventHandler) :
+        bus(bus),
+        event(event), config(buttonCfg), callbackHandler(handler)
+    {
+        int ret = -1;
+
+        // config group gpio based on the gpio defs read from the json file
+        ret = configGroupGpio(config);
+
+        if (ret < 0)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                (getFormFactorType() + " : failed to config GPIO").c_str());
+            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+                IOError();
+        }
+    }
+    virtual ~ButtonIface()
+    {
+    }
+
+    /**
+     * @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 evend handling logic along with
+     * init() function can be created to override the default event handling.
+     */
+
+    virtual void handleEvent(sd_event_source* es, int fd, uint32_t revents) = 0;
+    static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
+                            void* userdata)
+    {
+        if (userdata)
+        {
+
+            ButtonIface* buttonIface = static_cast<ButtonIface*>(userdata);
+            buttonIface->handleEvent(es, fd, revents);
+            return 0;
+        }
+    }
+
+    std::string getFormFactorType() const
+    {
+        return config.formFactorName;
+    }
+
+  protected:
+    /**
+     * @brief oem specific initialization can be done under init function.
+     * if platform specific initialization is needed then
+     * a derived class instance with its own init function to override the
+     * default init() method can be added.
+     */
+
+    virtual void init()
+    {
+
+        // initialize the button io fd from the buttonConfig
+        // which has fd stored when configGroupGpio is called
+        for (auto gpioCfg : config.gpios)
+        {
+            char buf;
+            int fd = gpioCfg.fd;
+
+            int ret = ::read(fd, &buf, sizeof(buf));
+            if (ret < 0)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    (getFormFactorType() + " : read error!").c_str());
+            }
+
+            ret = sd_event_add_io(event.get(), nullptr, fd, EPOLLPRI,
+                                  callbackHandler, this);
+            if (ret < 0)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    (getFormFactorType() + " : failed to add to event loop")
+                        .c_str());
+                ::closeGpio(fd);
+                throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+                    IOError();
+            }
+        }
+    }
+    /**
+     * @brief similar to init() oem specific deinitialization can be done under
+     * deInit function. if platform specific deinitialization is needed then a
+     * derived class instance with its own init function to override the default
+     * deinit() method can be added.
+     */
+    virtual void deInit()
+    {
+        for (auto gpioCfg : config.gpios)
+        {
+            ::closeGpio(gpioCfg.fd);
+        }
+    }
+
+    buttonConfig config;
+    sdbusplus::bus::bus& bus;
+    EventPtr& event;
+    sd_event_io_handler_t callbackHandler;
+};
diff --git a/inc/gpio.hpp b/inc/gpio.hpp
index ba4b8ad..ebaf3cf 100644
--- a/inc/gpio.hpp
+++ b/inc/gpio.hpp
@@ -42,14 +42,14 @@
  * @return int returns 0 on successful config of all gpios
  */
 
-int configGroupGpio(sdbusplus::bus::bus& bus, buttonConfig& buttonCfg);
+int configGroupGpio(buttonConfig& buttonCfg);
 
 /**
  * @brief  configures and initializes the single gpio
  * @return int returns 0 on successful config of all gpios
  */
 
-int configGpio(sdbusplus::bus::bus& bus, gpioInfo& gpioConfig);
+int configGpio(gpioInfo& gpioConfig);
 
 uint32_t getGpioNum(const std::string& gpioPin);
 void closeGpio(int fd);
diff --git a/inc/id_button.hpp b/inc/id_button.hpp
index cb32125..c58d264 100644
--- a/inc/id_button.hpp
+++ b/inc/id_button.hpp
@@ -15,6 +15,8 @@
 */
 
 #pragma once
+#include "button_factory.hpp"
+#include "button_interface.hpp"
 #include "common.hpp"
 #include "gpio.hpp"
 #include "xyz/openbmc_project/Chassis/Buttons/ID/server.hpp"
@@ -24,132 +26,40 @@
 
 #include <phosphor-logging/elog-errors.hpp>
 
-const static constexpr char* ID_BUTTON = "ID_BTN";
+static constexpr std::string_view ID_BUTTON = "ID_BTN";
 
-struct IDButton
-    : sdbusplus::server::object::object<
-          sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::ID>
+class IDButton
+    : public sdbusplus::server::object::object<
+          sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::ID>,
+      public ButtonIface
 {
 
+  public:
     IDButton(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
-             buttonConfig& buttonCfg,
-             sd_event_io_handler_t handler = IDButton::EventHandler) :
+             buttonConfig& buttonCfg) :
         sdbusplus::server::object::object<
             sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::ID>(
             bus, path),
-        fd(-1), buttonIFConfig(buttonCfg), bus(bus), event(event),
-        callbackHandler(handler)
+        ButtonIface(bus, event, buttonCfg)
     {
-
-        int ret = -1;
-
-        // config group gpio based on the gpio defs read from the json file
-        ret = configGroupGpio(bus, buttonIFConfig);
-
-        if (ret < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "ID_BUTTON: failed to config GPIO");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-        // initialize the button io fd from the buttonConfig
-        // which has fd stored when configGroupGpio is called
-        fd = buttonIFConfig.gpios[0].fd;
-
-        char buf;
-        ::read(fd, &buf, sizeof(buf));
-
-        ret = sd_event_add_io(event.get(), nullptr, fd, EPOLLPRI,
-                              callbackHandler, this);
-        if (ret < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "ID_BUTTON: failed to add to event loop");
-            ::closeGpio(fd);
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
+        init();
     }
 
     ~IDButton()
     {
-        ::closeGpio(fd);
+        deInit();
     }
 
     void simPress() override;
 
-    static const std::string getGpioName()
+    static constexpr std::string_view getFormFactorName()
     {
         return ID_BUTTON;
     }
-
-    static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
-                            void* userdata)
+    static constexpr const char* getDbusObjectPath()
     {
-
-        int n = -1;
-        char buf = '0';
-
-        if (!userdata)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "ID_BUTTON: userdata null!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        IDButton* idButton = static_cast<IDButton*>(userdata);
-
-        if (!idButton)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "ID_BUTTON: null pointer!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        n = ::lseek(fd, 0, SEEK_SET);
-
-        if (n < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "ID_BUTTON: lseek error!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        n = ::read(fd, &buf, sizeof(buf));
-        if (n < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "ID_BUTTON: read error!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        if (buf == '0')
-        {
-            phosphor::logging::log<phosphor::logging::level::DEBUG>(
-                "ID_BUTTON: pressed");
-            // emit pressed signal
-            idButton->pressed();
-        }
-        else
-        {
-            phosphor::logging::log<phosphor::logging::level::DEBUG>(
-                "ID_BUTTON: released");
-            // released
-            idButton->released();
-        }
-
-        return 0;
+        return ID_DBUS_OBJECT_NAME;
     }
 
-  private:
-    int fd;
-    buttonConfig buttonIFConfig;
-    sdbusplus::bus::bus& bus;
-    EventPtr& event;
-    sd_event_io_handler_t callbackHandler;
+    void handleEvent(sd_event_source* es, int fd, uint32_t revents) override;
 };
diff --git a/inc/power_button.hpp b/inc/power_button.hpp
index 283b149..bef2662 100644
--- a/inc/power_button.hpp
+++ b/inc/power_button.hpp
@@ -15,6 +15,8 @@
 */
 
 #pragma once
+#include "button_factory.hpp"
+#include "button_interface.hpp"
 #include "common.hpp"
 #include "gpio.hpp"
 #include "xyz/openbmc_project/Chassis/Buttons/Power/server.hpp"
@@ -25,159 +27,45 @@
 #include <chrono>
 #include <phosphor-logging/elog-errors.hpp>
 
-const static constexpr char* POWER_BUTTON = "POWER_BUTTON";
+static constexpr std::string_view POWER_BUTTON = "POWER_BUTTON";
 
-struct PowerButton
-    : sdbusplus::server::object::object<
-          sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Power>
+class PowerButton
+    : public sdbusplus::server::object::object<
+          sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Power>,
+      public ButtonIface
 {
-
+  public:
     PowerButton(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
-                buttonConfig& buttonCfg,
-                sd_event_io_handler_t handler = PowerButton::EventHandler) :
+                buttonConfig& buttonCfg) :
         sdbusplus::server::object::object<
             sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Power>(
             bus, path),
-        fd(-1), buttonIFConfig(buttonCfg), bus(bus), event(event),
-        callbackHandler(handler)
+        ButtonIface(bus, event, buttonCfg)
     {
-
-        int ret = -1;
-
-        // config group gpio based on the gpio defs read from the json file
-        ret = configGroupGpio(bus, buttonIFConfig);
-
-        if (ret < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "POWER_BUTTON: failed to config GPIO");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        // initialize the button io fd from the buttonConfig
-        // which has fd stored when configGroupGpio is called
-        fd = buttonIFConfig.gpios[0].fd;
-
-        char buf;
-        ::read(fd, &buf, sizeof(buf));
-
-        ret = sd_event_add_io(event.get(), nullptr, fd, EPOLLPRI,
-                              callbackHandler, this);
-        if (ret < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "POWER_BUTTON: failed to add to event loop");
-            ::closeGpio(fd);
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
+        init();
     }
 
     ~PowerButton()
     {
-        ::closeGpio(fd);
+
+        deInit();
     }
 
     void simPress() override;
     void simLongPress() override;
 
-    static const std::string getGpioName()
+    static constexpr std::string_view getFormFactorName()
     {
         return POWER_BUTTON;
     }
-
-    void updatePressedTime()
+    static constexpr const char* getDbusObjectPath()
     {
-        pressedTime = std::chrono::steady_clock::now();
+        return POWER_DBUS_OBJECT_NAME;
     }
+    void updatePressedTime();
+    auto getPressTime() const;
+    void handleEvent(sd_event_source* es, int fd, uint32_t revents) override;
 
-    auto getPressTime() const
-    {
-        return pressedTime;
-    }
-
-    static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
-                            void* userdata)
-    {
-
-        int n = -1;
-        char buf = '0';
-
-        if (!userdata)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "POWER_BUTTON: userdata null!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        PowerButton* powerButton = static_cast<PowerButton*>(userdata);
-
-        if (!powerButton)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "POWER_BUTTON: null pointer!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        n = ::lseek(fd, 0, SEEK_SET);
-
-        if (n < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "POWER_BUTTON: lseek error!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        n = ::read(fd, &buf, sizeof(buf));
-        if (n < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "POWER_BUTTON: read error!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        if (buf == '0')
-        {
-            phosphor::logging::log<phosphor::logging::level::DEBUG>(
-                "POWER_BUTTON: pressed");
-
-            powerButton->updatePressedTime();
-            // emit pressed signal
-            powerButton->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 - powerButton->getPressTime());
-
-            if (d > std::chrono::milliseconds(LONG_PRESS_TIME_MS))
-            {
-                powerButton->pressedLong();
-            }
-            else
-            {
-                // released
-                powerButton->released();
-            }
-        }
-
-        return 0;
-    }
-
-  private:
-    int fd;
-    buttonConfig buttonIFConfig; // button iface io details
-    sdbusplus::bus::bus& bus;
-    EventPtr& event;
-    sd_event_io_handler_t callbackHandler;
+  protected:
     decltype(std::chrono::steady_clock::now()) pressedTime;
 };
diff --git a/inc/reset_button.hpp b/inc/reset_button.hpp
index 478628b..8e15740 100644
--- a/inc/reset_button.hpp
+++ b/inc/reset_button.hpp
@@ -15,6 +15,8 @@
 */
 
 #pragma once
+#include "button_factory.hpp"
+#include "button_interface.hpp"
 #include "common.hpp"
 #include "gpio.hpp"
 #include "xyz/openbmc_project/Chassis/Buttons/Reset/server.hpp"
@@ -24,133 +26,40 @@
 
 #include <phosphor-logging/elog-errors.hpp>
 
-const static constexpr char* RESET_BUTTON = "RESET_BUTTON";
+static constexpr std::string_view RESET_BUTTON = "RESET_BUTTON";
 
-struct ResetButton
-    : sdbusplus::server::object::object<
-          sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Reset>
+class ResetButton
+    : public sdbusplus::server::object::object<
+          sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Reset>,
+      public ButtonIface
 {
-
+  public:
     ResetButton(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
-                buttonConfig& buttonCfg,
-                sd_event_io_handler_t handler = ResetButton::EventHandler) :
+                buttonConfig& buttonCfg) :
         sdbusplus::server::object::object<
             sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Reset>(
             bus, path),
-        fd(-1), buttonIFConfig(buttonCfg), bus(bus), event(event),
-        callbackHandler(handler)
+        ButtonIface(bus, event, buttonCfg)
     {
-
-        int ret = -1;
-
-        // config group gpio based on the gpio defs read from the json file
-        ret = configGroupGpio(bus, buttonIFConfig);
-
-        if (ret < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "RESET_BUTTON: failed to config GPIO");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        // initialize the button io fd from the buttonConfig
-        // which has fd stored when configGroupGpio is called
-        fd = buttonIFConfig.gpios[0].fd;
-
-        char buf;
-        ::read(fd, &buf, sizeof(buf));
-
-        ret = sd_event_add_io(event.get(), nullptr, fd, EPOLLPRI,
-                              callbackHandler, this);
-        if (ret < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "RESET_BUTTON: failed to add to event loop");
-            ::closeGpio(fd);
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
+        init();
     }
 
     ~ResetButton()
     {
-        ::closeGpio(fd);
+        deInit();
     }
 
     void simPress() override;
 
-    static const std::string getGpioName()
+    static constexpr std::string_view getFormFactorName()
     {
         return RESET_BUTTON;
     }
 
-    static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
-                            void* userdata)
+    static constexpr const char* getDbusObjectPath()
     {
-
-        int n = -1;
-        char buf = '0';
-
-        if (!userdata)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "RESET_BUTTON: userdata null!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        ResetButton* resetButton = static_cast<ResetButton*>(userdata);
-
-        if (!resetButton)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "RESET_BUTTON: null pointer!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        n = ::lseek(fd, 0, SEEK_SET);
-
-        if (n < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "RESET_BUTTON: lseek error!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        n = ::read(fd, &buf, sizeof(buf));
-        if (n < 0)
-        {
-            phosphor::logging::log<phosphor::logging::level::ERR>(
-                "RESET_BUTTON: read error!");
-            throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
-                IOError();
-        }
-
-        if (buf == '0')
-        {
-            phosphor::logging::log<phosphor::logging::level::DEBUG>(
-                "RESET_BUTTON: pressed");
-            // emit pressed signal
-            resetButton->pressed();
-        }
-        else
-        {
-            phosphor::logging::log<phosphor::logging::level::DEBUG>(
-                "RESET_BUTTON: released");
-            // released
-            resetButton->released();
-        }
-
-        return 0;
+        return RESET_DBUS_OBJECT_NAME;
     }
 
-  private:
-    int fd;
-    buttonConfig buttonIFConfig; // button iface io details
-    sdbusplus::bus::bus& bus;
-    EventPtr& event;
-    sd_event_io_handler_t callbackHandler;
+    void handleEvent(sd_event_source* es, int fd, uint32_t revents) override;
 };
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;
+}