Add Timer class

This class is used to call a callback function
when the timer expires.  It can be one shot, or repeating.

Copied from the phosphor-fan-presence repository.

Change-Id: I9d63c2e6fd550286a2a5360e1e8d13f6a3c25923
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1f4edce
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+*.o
+*.lo
+*.la
+*.sw*
+Makefile
+Makefile.in
+configure
+.deps
+.libs
+aclocal.m4
+ar-lib
+arm-openbmc-linux-gnueabi-libtool
+autom4te.cache/
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+depcomp
+install-sh
+i586-openbmc-linux-libtool
+ltmain.sh
+missing
+stamp-h1
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..ef4d98b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,14 @@
+AM_DEFAULT_SOURCE_EXT = .cpp
+
+noinst_LTLIBRARIES = libpower.la
+libpower_la_LDFLAGS = -static
+libpower_la_LIBADD = \
+	$(PHOSPHOR_LOGGING_LIBS) \
+	$(SDBUSPLUS_LIBS)
+libpower_la_CXXFLAGS = \
+	$(PHOSPHOR_LOGGING_CFLAGS) \
+	$(SDBUSPLUS_CFLAGS)
+
+libpower_la_SOURCES = timer.cpp
+
+SUBDIRS = .
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..4c0b0f5
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+AUTOCONF_FILES="Makefile.in aclocal.m4 ar-lib autom4te.cache compile \
+        config.guess config.h.in config.h.in~ config.sub configure depcomp \
+        install-sh ltmain.sh missing *libtool"
+
+case $1 in
+    clean)
+        test -f Makefile && make maintainer-clean
+        for file in ${AUTOCONF_FILES}; do
+            find -name "$file" | xargs -r rm -rf
+        done
+        exit 0
+        ;;
+esac
+
+autoreconf -if
+echo 'Run "./configure ${CONFIGURE_FLAGS} && make"'
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..7a2f09b
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,32 @@
+# Initialization
+AC_PREREQ([2.69])
+AC_INIT([witherspoon-pfault-analysis], [1.0],
+[https://github.com/openbmc/witherspoon-pfault-analysis/issues])
+AC_LANG([C++])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign dist-xz])
+AM_SILENT_RULES([yes])
+
+# Checks for programs.
+AC_PROG_CXX
+AM_PROG_AR
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+# Checks for typedefs, structures, and compiler characteristics.
+AX_CXX_COMPILE_STDCXX_14([noext])
+AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
+
+PKG_CHECK_MODULES([SDBUSPLUS], [sdbusplus],,
+    AC_MSG_ERROR(["Requires sdbusplus package."]))
+PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],,\
+    AC_MSG_ERROR(["Requires phosphor-logging package."]))
+PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces],,\
+    AC_MSG_ERROR(["Requires phosphor-dbus-interfaces package."]))
+
+# Checks for library functions.
+LT_INIT # Required for systemd linking
+
+# Create configured output
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/event.hpp b/event.hpp
new file mode 100644
index 0000000..6b2c95f
--- /dev/null
+++ b/event.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <memory>
+#include <systemd/sd-event.h>
+
+namespace witherspoon
+{
+namespace power
+{
+namespace event
+{
+
+/**
+ * Custom deleter for sd_event_source
+ */
+struct EventSourceDeleter
+{
+    void operator()(sd_event_source* eventSource) const
+    {
+        sd_event_source_unref(eventSource);
+    }
+};
+
+using EventSource = std::unique_ptr<sd_event_source, EventSourceDeleter>;
+
+/**
+ * Customer deleter for sd_event
+ */
+struct EventDeleter
+{
+    void operator()(sd_event* event) const
+    {
+        sd_event_unref(event);
+    }
+};
+
+using Event = std::unique_ptr<sd_event, EventDeleter>;
+
+}
+}
+}
diff --git a/timer.cpp b/timer.cpp
new file mode 100644
index 0000000..7039338
--- /dev/null
+++ b/timer.cpp
@@ -0,0 +1,170 @@
+/**
+ * Copyright © 2017 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <chrono>
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+#include <type_traits>
+#include "timer.hpp"
+
+namespace witherspoon
+{
+namespace power
+{
+
+using namespace phosphor::logging;
+using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
+                            Error::InternalFailure;
+
+Timer::Timer(event::Event& events,
+             std::function<void()> callbackFunc) :
+    timeEvent(events),
+    callback(callbackFunc),
+    timeout(0)
+{
+    sd_event_source* source = nullptr;
+
+    // Start with an infinite expiration time
+    auto r = sd_event_add_time(timeEvent.get(),
+                               &source,
+                               CLOCK_MONOTONIC, // Time base
+                               UINT64_MAX,      // Expire time - way long time
+                               0,               // Use default event accuracy
+                               timeoutHandler,  // Callback handler on timeout
+                               this);           // User data
+    if (r < 0)
+    {
+        log<level::ERR>("Timer::Timer failed call to sd_event_add_time",
+                        entry("ERROR=%s", strerror(-r)));
+        elog<InternalFailure>();
+    }
+
+    eventSource.reset(source);
+
+    //Ensure timer isn't running
+    setTimer(SD_EVENT_OFF);
+}
+
+
+Timer::~Timer()
+{
+    setTimer(SD_EVENT_OFF);
+}
+
+
+int Timer::timeoutHandler(sd_event_source* eventSource,
+                          uint64_t usec, void* userData)
+{
+    auto timer = static_cast<Timer*>(userData);
+
+    if (timer->type == TimerType::repeating)
+    {
+        //Set the next expiration time
+        timer->setTimeout();
+    }
+
+    timer->callback();
+
+    return 0;
+}
+
+
+std::chrono::microseconds Timer::getTime()
+{
+    using namespace std::chrono;
+    auto now = steady_clock::now().time_since_epoch();
+    return duration_cast<microseconds>(now);
+}
+
+
+void Timer::setTimer(int action)
+{
+    auto r = sd_event_source_set_enabled(eventSource.get(), action);
+    if (r < 0)
+    {
+        log<level::ERR>("Failed call to sd_event_source_set_enabled",
+                        entry("ERROR=%s", strerror(-r)),
+                        entry("ACTION=%d", action));
+        elog<InternalFailure>();
+    }
+}
+
+
+void Timer::stop()
+{
+    setTimer(SD_EVENT_OFF);
+}
+
+
+bool Timer::running()
+{
+    int status = 0;
+
+    //returns SD_EVENT_OFF, SD_EVENT_ON, or SD_EVENT_ONESHOT
+    auto r = sd_event_source_get_enabled(eventSource.get(), &status);
+    if (r < 0)
+    {
+        log<level::ERR>("Failed call to sd_event_source_get_enabled",
+                        entry("ERROR=%s", strerror(-r)));
+        elog<InternalFailure>();
+    }
+
+    return (status != SD_EVENT_OFF);
+}
+
+
+void Timer::setTimeout()
+{
+    //Get the current time and add the delta
+    static_assert(std::is_same<decltype(getTime()),
+            std::chrono::microseconds>::value,
+            "Timer::getTime() is the wrong type");
+    static_assert(std::is_same<decltype(timeout),
+            std::chrono::microseconds>::value,
+            "Timer::timeout is the wrong type");
+
+    auto expireTime = getTime() + timeout;
+
+    //Set the time
+    auto r = sd_event_source_set_time(eventSource.get(), expireTime.count());
+    if (r < 0)
+    {
+        log<level::ERR>("Failed call to sd_event_source_set_time",
+                        entry("ERROR=%s", strerror(-r)));
+        elog<InternalFailure>();
+    }
+}
+
+
+void Timer::start(std::chrono::microseconds timeValue,
+                  TimerType timerType)
+{
+    type = timerType;
+
+    // Disable the timer
+    setTimer(SD_EVENT_OFF);
+
+    //Rearm the timer
+    timeout = timeValue;
+    setTimeout();
+
+    setTimer((type == TimerType::oneshot) ? SD_EVENT_ONESHOT : SD_EVENT_ON);
+}
+
+
+}
+}
diff --git a/timer.hpp b/timer.hpp
new file mode 100644
index 0000000..0f46de7
--- /dev/null
+++ b/timer.hpp
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include "event.hpp"
+
+namespace witherspoon
+{
+namespace power
+{
+
+
+/**
+ * @class Timer
+ *
+ * This class implements a simple timer that runs an arbitrary
+ * function on expiration.  The timeout value is set in microseconds.
+ * It can be stopped while it is running, and queried to see if it is
+ * running.
+ *
+ * If started with the 'repeating' argument, it will keep calling the
+ * callback function every <timeout> microseconds.  If started with the
+ * 'oneshot' argument, it will just call the callback function one time.
+ *
+ * It needs an sd_event loop to function.
+ */
+class Timer
+{
+    public:
+
+        enum class TimerType
+        {
+            oneshot,
+            repeating
+        };
+
+        Timer() = delete;
+        Timer(const Timer&) = delete;
+        Timer& operator=(const Timer&) = delete;
+        Timer(Timer&&) = default;
+        Timer& operator=(Timer&&) = default;
+
+        /**
+         * @brief Constructs timer object
+         *
+         * @param[in] events - sd_event pointer, previously created
+         * @param[in] callbackFunc - The function to call on timer expiration
+         */
+        Timer(event::Event& events,
+              std::function<void()> callbackFunc);
+
+        /**
+         * @brief Destructor
+         */
+        ~Timer();
+
+        /**
+         * @brief Starts the timer
+         *
+         * The input is an offset from the current steady clock.
+         *
+         * @param[in] usec - the timeout value in microseconds
+         * @param[in] type - either a oneshot, or repeating
+         */
+        void start(std::chrono::microseconds usec,
+                   TimerType type = TimerType::oneshot);
+
+        /**
+         * @brief Stop the timer
+         */
+        void stop();
+
+        /**
+         * @brief Returns true if the timer is running
+         */
+        bool running();
+
+        /**
+         * @brief Returns the timeout value
+         *
+         * @return - the last value sent in via start().
+         */
+         inline auto getTimeout() const
+         {
+            return timeout;
+         }
+
+        /**
+         * @brief Returns the timer type
+         */
+        inline auto getType() const
+        {
+            return type;
+        }
+
+    private:
+
+        /**
+         * @brief Callback function when timer goes off
+         *
+         * Calls the callback function passed in by the user.
+         *
+         * @param[in] eventSource - Source of the event
+         * @param[in] usec        - time in micro seconds
+         * @param[in] userData    - User data pointer
+         */
+        static int timeoutHandler(sd_event_source* eventSource,
+                                  uint64_t usec, void* userData);
+
+        /**
+         * @brief Gets the current time from the steady clock
+         */
+        std::chrono::microseconds getTime();
+
+        /**
+         * @brief Wrapper around sd_event_source_set_enabled
+         *
+         * @param[in] action - either SD_EVENT_OFF, SD_EVENT_ON,
+         *                     or SD_EVENT_ONESHOT
+         */
+        void setTimer(int action);
+
+
+        /**
+         * @brief Sets the expiration time for the timer
+         *
+         * Sets it to timeout microseconds in the future
+         */
+        void setTimeout();
+
+        /**
+         * @brief The sd_event structure
+         */
+        event::Event& timeEvent;
+
+        /**
+         * @brief Source of events
+         */
+        event::EventSource eventSource;
+
+        /**
+         * @brief Either 'repeating' or 'oneshot'
+         */
+        TimerType type = TimerType::oneshot;
+
+        /**
+         * @brief The function to call when the timer expires
+         */
+        std::function<void()> callback;
+
+        /**
+         * @brief What the timer was set to run for
+         *
+         * Not cleared on timer expiration
+         */
+        std::chrono::microseconds timeout;
+};
+
+}
+}