Refactor GPIO Monitor class

Refactor the GPIO Monitor class to use a common class, Evdev,
to inherit from. Evdev does the basic libevdev handling.

Change-Id: I427aa9720b0bbbea0284c0babcc03ece92e55f5e
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index bbe24fc..fbe96e2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,15 +5,18 @@
 phosphor_gpio_monitor_SOURCES = \
 				argument.cpp \
 				monitor.cpp \
+				evdev.cpp \
 				mainapp.cpp
 
 phosphor_gpio_monitor_LDFLAGS = $(SYSTEMD_LIBS) \
                                 $(SDBUSPLUS_LIBS) \
                                 $(PHOSPHOR_LOGGING_LIBS) \
+                                $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
                                 $(LIBEVDEV_LIBS)
 
 phosphor_gpio_monitor_CXXFLAGS = $(SYSTEMD_CFLAGS) \
                                  $(SDBUSPLUS_CFLAGS) \
+                                 $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \
                                  $(PHOSPHOR_LOGGING_CFLAGS) \
                                  $(LIBEVDEV_CFLAGS)
 
diff --git a/evdev.hpp b/evdev.hpp
index b3189f1..353c593 100644
--- a/evdev.hpp
+++ b/evdev.hpp
@@ -70,8 +70,7 @@
          *  @param[in] path      - Device path to read for GPIO pin state
          *  @param[in] key       - GPIO key to monitor
          *  @param[in] event     - sd_event handler
-         *  @param[in] handler   - IO callback handler. Defaults to one in this
-         *                        class
+         *  @param[in] handler   - IO callback handler.
          *  @param[in] useEvDev  - Whether to use EvDev to retrieve events
          */
         Evdev(const std::string& path,
diff --git a/monitor.cpp b/monitor.cpp
index 632506b..5bc4742 100644
--- a/monitor.cpp
+++ b/monitor.cpp
@@ -31,59 +31,6 @@
 
 using namespace phosphor::logging;
 
-// Populate the file descriptor for passed in device
-int Monitor::openDevice()
-{
-    using namespace phosphor::logging;
-
-    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
-    if (fd < 0)
-    {
-        log<level::ERR>("Failed to open device",
-                entry("PATH=%s", path.c_str()));
-        throw std::runtime_error("Failed to open device");
-    }
-    return fd;
-}
-
-// Attaches the FD to event loop and registers the callback handler
-void Monitor::registerCallback()
-{
-    decltype(eventSource.get()) sourcePtr = nullptr;
-    auto r = sd_event_add_io(event.get(), &sourcePtr, (fd)(),
-                             EPOLLIN, callbackHandler, this);
-    eventSource.reset(sourcePtr);
-
-    if (r < 0)
-    {
-        log<level::ERR>("Failed to register callback handler",
-                entry("ERROR=%s", strerror(-r)));
-        throw std::runtime_error("Failed to register callback handler");
-    }
-}
-
-// Initializes the event device with the fd
-void Monitor::initEvDev()
-{
-    if (device)
-    {
-        // Init can be done only once per device
-        return;
-    }
-
-    struct libevdev* evdev = nullptr;
-    auto rc = libevdev_new_from_fd((fd)(), &evdev);
-    if (rc < 0)
-    {
-        log<level::ERR>("Failed to initialize evdev");
-        throw std::runtime_error("Failed to initialize evdev");
-    }
-
-    // Packing in the unique_ptr
-    device.reset(evdev);
-    evdev = nullptr;
-}
-
 // Callback handler when there is an activity on the FD
 int Monitor::processEvents(sd_event_source* es, int fd,
                            uint32_t revents, void* userData)
@@ -107,7 +54,7 @@
     while (rc >= 0)
     {
         // Wait until no more events are available on the device.
-        rc = libevdev_next_event(device.get(),
+        rc = libevdev_next_event(devicePtr.get(),
                                  LIBEVDEV_READ_FLAG_NORMAL, &ev);
         if (rc < 0)
         {
diff --git a/monitor.hpp b/monitor.hpp
index bffb1d4..1dcef79 100644
--- a/monitor.hpp
+++ b/monitor.hpp
@@ -3,50 +3,20 @@
 #include <unistd.h>
 #include <string>
 #include <linux/input.h>
-#include <libevdev/libevdev.h>
 #include <systemd/sd-event.h>
 #include <sdbusplus/bus.hpp>
-#include "file.hpp"
+#include "evdev.hpp"
+
 namespace phosphor
 {
 namespace gpio
 {
 
-/* Need a custom deleter for freeing up sd_event */
-struct EventDeleter
-{
-    void operator()(sd_event* event) const
-    {
-        event = sd_event_unref(event);
-    }
-};
-using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
-
-/* Need a custom deleter for freeing up sd_event_source */
-struct EventSourceDeleter
-{
-    void operator()(sd_event_source* eventSource) const
-    {
-        eventSource = sd_event_source_unref(eventSource);
-    }
-};
-using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>;
-
-/* Need a custom deleter for freeing up evdev struct */
-struct EvdevDeleter
-{
-    void operator()(struct libevdev* device) const
-    {
-        libevdev_free(device);
-    }
-};
-using EvdevPtr = std::unique_ptr<struct libevdev, EvdevDeleter>;
-
 /** @class Monitor
  *  @brief Responsible for catching GPIO state change
- *  condition and taking actions
+ *  condition and starting systemd targets.
  */
-class Monitor
+class Monitor : public Evdev
 {
     public:
         Monitor() = delete;
@@ -75,23 +45,9 @@
                 EventPtr& event,
                 sd_event_io_handler_t handler = Monitor::processEvents,
                 bool useEvDev = true)
-            : path(path),
-              key(key),
+            : Evdev(path, key, event, handler, useEvDev),
               polarity(polarity),
-              target(target),
-              event(event),
-              callbackHandler(handler),
-              fd(openDevice())
-        {
-            if (useEvDev)
-            {
-                // If we are asked to use EvDev, do that initialization.
-                initEvDev();
-            }
-
-            // And register callback handler when FD has some data
-            registerCallback();
-        }
+              target(target) {};
 
         /** @brief Callback handler when the FD has some activity on it
          *
@@ -113,47 +69,17 @@
         }
 
     private:
-        /** @brief Absolute path of GPIO input device */
-        const std::string& path;
-
-        /** @brief GPIO key code that is of interest */
-        decltype(input_event::code) key;
-
         /** @brief GPIO key value that is of interest */
         decltype(input_event::value) polarity;
 
         /** @brief Systemd unit to be started when the condition is met */
         const std::string& target;
 
-        /** @brief Monitor to sd_event */
-        EventPtr& event;
-
-        /** @brief event source */
-        EventSourcePtr eventSource;
-
-        /** @brief Callback handler when the FD has some data */
-        sd_event_io_handler_t callbackHandler;
-
-        /** @brief File descriptor manager */
-        FileDescriptor fd;
-
-        /** event structure */
-        EvdevPtr device;
-
         /** @brief Completion indicator */
         bool complete = false;
 
-        /** @brief Opens the device and populates the descriptor */
-        int openDevice();
-
-        /** @brief attaches FD to events and sets up callback handler */
-        void registerCallback();
-
         /** @brief Analyzes the GPIO event and starts configured target */
         void analyzeEvent();
-
-        /** @brief Initializes evdev handle with the fd */
-        void initEvDev();
 };
 
 } // namespace gpio
diff --git a/test/Makefile.am b/test/Makefile.am
index 5bd15e7..ff34005 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -7,7 +7,8 @@
 # # Build/add utest to test suite
 check_PROGRAMS = utest
 utest_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS) $(PHOSPHOR_LOGGING_CFLAGS) $(LIBEVDEV_CFLAGS)
-utest_CXXFLAGS = $(PTHREAD_CFLAGS)
-utest_LDFLAGS = -lgtest_main -lgtest $(PTHREAD_LIBS) $(OESDK_TESTCASE_FLAGS) $(SYSTEMD_LIBS) $(PHOSPHOR_LOGGING_LIBS) $(LIBEVDEV_LIBS)
+utest_CXXFLAGS = $(PTHREAD_CFLAGS) $(LIBEVDEV_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+utest_LDFLAGS = -lgtest_main -lgtest $(PTHREAD_LIBS) $(OESDK_TESTCASE_FLAGS) $(SYSTEMD_LIBS) $(PHOSPHOR_LOGGING_LIBS) \
+$(LIBEVDEV_LIBS) $(PHOSPHOR_DBUS_INTERFACES_LIBS)
 utest_SOURCES = utest.cpp
-utest_LDADD = $(top_builddir)/monitor.o
+utest_LDADD = $(top_builddir)/monitor.o $(top_srcdir)/evdev.cpp
diff --git a/test/utest.cpp b/test/utest.cpp
index 3728244..c6b6f18 100644
--- a/test/utest.cpp
+++ b/test/utest.cpp
@@ -5,6 +5,7 @@
 #include <linux/input.h>
 #include <gtest/gtest.h>
 #include "monitor.hpp"
+#include "evdev.hpp"
 
 using namespace phosphor::gpio;