Define a mode for tach sensor timer

Use a single timer on the tach sensors for delaying both nonfunctional
and functional state changes by declaring what mode the timer is in.
Since a fan is either transitioning from a functional state to a
nonfunctional state or vice-versa, enabling the timer in the mode
requested allows the user to define a delay for both of these transition
states.

Tested: Current nonfunctional timer delay operates the same

Change-Id: I0c165355d41d27e1906918953e5226968062ee16
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/monitor/fan.cpp b/monitor/fan.cpp
index 228ecd3..96db76c 100644
--- a/monitor/fan.cpp
+++ b/monitor/fan.cpp
@@ -112,7 +112,7 @@
     {
         if (sensor.functional() && !running)
         {
-            sensor.startTimer();
+            sensor.startTimer(TimerMode::nonfunc);
         }
     }
     else
diff --git a/monitor/tach_sensor.cpp b/monitor/tach_sensor.cpp
index 03c34e2..5e985d0 100644
--- a/monitor/tach_sensor.cpp
+++ b/monitor/tach_sensor.cpp
@@ -15,6 +15,7 @@
  */
 #include <experimental/filesystem>
 #include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog.hpp>
 #include "fan.hpp"
 #include "sdbusplus.hpp"
 #include "tach_sensor.hpp"
@@ -32,6 +33,8 @@
 constexpr auto FAN_VALUE_PROPERTY = "Value";
 
 using namespace std::experimental::filesystem;
+using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
+                            Error::InternalFailure;
 
 /**
  * @brief Helper function to read a property
@@ -84,6 +87,7 @@
     _factor(factor),
     _offset(offset),
     _timeout(timeout),
+    _timerMode(TimerMode::func),
     _timer(events, [this, &fan](){ fan.timerExpired(*this); })
 {
     // Start from a known state of functional
@@ -212,12 +216,45 @@
    _fan.tachChanged(*this);
 }
 
+void TachSensor::startTimer(TimerMode mode)
+{
+    if (!timerRunning())
+    {
+        _timer.start(
+                getDelay(mode),
+                util::Timer::TimerType::oneshot);
+        _timerMode = mode;
+    }
+    else
+    {
+        if (mode != _timerMode)
+        {
+            _timer.stop();
+            _timer.start(
+                    getDelay(mode),
+                    util::Timer::TimerType::oneshot);
+            _timerMode = mode;
+        }
+    }
+}
 
-std::chrono::microseconds TachSensor::getTimeout()
+std::chrono::microseconds TachSensor::getDelay(TimerMode mode)
 {
     using namespace std::chrono;
 
-    return duration_cast<microseconds>(seconds(_timeout));
+    switch(mode)
+    {
+        case TimerMode::nonfunc :
+                return duration_cast<microseconds>(seconds(_timeout));
+        case TimerMode::func :
+                return duration_cast<microseconds>(seconds(_funcDelay));
+        default :
+                // Log an internal error for undefined timer mode
+                log<level::ERR>("Undefined timer mode",
+                        entry("TIMER_MODE=%u", mode));
+                elog<InternalFailure>();
+                return duration_cast<microseconds>(seconds(0));
+    }
 }
 
 void TachSensor::updateInventory(bool functional)
diff --git a/monitor/tach_sensor.hpp b/monitor/tach_sensor.hpp
index ed8caf8..f59f6f5 100644
--- a/monitor/tach_sensor.hpp
+++ b/monitor/tach_sensor.hpp
@@ -29,6 +29,17 @@
 };
 
 /**
+ * The mode that the timer is running in:
+ *   - func - Transition to functional state timer
+ *   - nonfunc - Transition to nonfunctional state timer
+ */
+enum class TimerMode
+{
+    func,
+    nonfunc
+};
+
+/**
  * @class TachSensor
  *
  * This class represents the sensor that reads a tach value.
@@ -151,15 +162,12 @@
         }
 
         /**
-         * @brief Starts the timer for the amount of time
-         *        specified in the constructor
+         * @brief Stops the timer when the given mode differs and starts
+         * the associated timer for the mode given if not already running
+         *
+         * @param[in] mode - mode of timer to start
          */
-        inline void startTimer()
-        {
-            _timer.start(
-                    getTimeout(),
-                    phosphor::fan::util::Timer::TimerType::oneshot);
-        }
+        void startTimer(TimerMode mode);
 
         /**
          * @brief Stops the timer
@@ -170,9 +178,11 @@
         }
 
         /**
-         * @brief Returns the timeout value to use for the sensor
+         * @brief Return the given timer mode's delay time
+         *
+         * @param[in] mode - mode of timer to get delay time for
          */
-        std::chrono::microseconds getTimeout();
+        std::chrono::microseconds getDelay(TimerMode mode);
 
         /**
          * Returns the sensor name
@@ -285,6 +295,11 @@
         const size_t _timeout;
 
         /**
+         * @brief Mode that current timer is in
+         */
+        TimerMode _timerMode;
+
+        /**
          * The timer object
          */
         phosphor::fan::util::Timer _timer;
diff --git a/monitor/trust_group.hpp b/monitor/trust_group.hpp
index a41520a..07d6a0e 100644
--- a/monitor/trust_group.hpp
+++ b/monitor/trust_group.hpp
@@ -142,7 +142,8 @@
                                 s.sensor->getInput()) !=
                                     s.sensor->getTarget())
                         {
-                            s.sensor->startTimer();
+                            s.sensor->startTimer(
+                                phosphor::fan::monitor::TimerMode::nonfunc);
                         }
                     });
         }