Timer to decrease fan speeds

Create a repeating timer for decreasing fan speeds where the fan speeds
in the zone are decreased when the timer expires and a decrease speed
request exists with no increase request present or active.

Change-Id: I419592f6f50c0ed524f8bf3ebf183854ab5ef2ea
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/main.cpp b/control/main.cpp
index 413a419..cde71d0 100644
--- a/control/main.cpp
+++ b/control/main.cpp
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 #include <sdbusplus/bus.hpp>
+#include <phosphor-logging/log.hpp>
 #include "argument.hpp"
 #include "manager.hpp"
+#include "event.hpp"
 
 using namespace phosphor::fan::control;
+using namespace phosphor::logging;
 
 int main(int argc, char* argv[])
 {
     auto bus = sdbusplus::bus::new_default();
+    sd_event* events = nullptr;
     phosphor::fan::util::ArgumentParser args(argc, argv);
 
     if (argc != 2)
@@ -46,7 +50,21 @@
         exit(-1);
     }
 
-    Manager manager(bus, mode);
+    auto r = sd_event_default(&events);
+    if (r < 0)
+    {
+        log<level::ERR>("Failed call to sd_event_default()",
+                        entry("ERROR=%s", strerror(-r)));
+        return -1;
+    }
+
+    phosphor::fan::event::EventPtr eventPtr{events};
+
+    //Attach the event object to the bus object so we can
+    //handle both sd_events (for the timers) and dbus signals.
+    bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
+
+    Manager manager(bus, eventPtr, mode);
 
     //Init mode will just set fans to max and delay
     if (mode == Mode::init)
@@ -54,12 +72,15 @@
         manager.doInit();
         return 0;
     }
-
-    while (true)
+    else
     {
-        bus.process_discard();
-        bus.wait();
+        r = sd_event_loop(eventPtr.get());
+        if (r < 0)
+        {
+            log<level::ERR>("Failed call to sd_event_loop",
+                            entry("ERROR=%s", strerror(-r)));
+        }
     }
 
-    return 0;
+    return -1;
 }
diff --git a/control/manager.cpp b/control/manager.cpp
index bbd0f5e..d5f97d7 100644
--- a/control/manager.cpp
+++ b/control/manager.cpp
@@ -119,6 +119,7 @@
 
 //Note: Future code will check 'mode' before starting control algorithm
 Manager::Manager(sdbusplus::bus::bus& bus,
+                 phosphor::fan::event::EventPtr& events,
                  Mode mode) :
     _bus(bus)
 {
@@ -142,7 +143,7 @@
             for (auto& z : zones)
             {
                 _zones.emplace(std::get<zoneNumPos>(z),
-                               std::make_unique<Zone>(mode, _bus, z));
+                               std::make_unique<Zone>(mode, _bus, events, z));
             }
 
             break;
diff --git a/control/manager.hpp b/control/manager.hpp
index 521b4cd..d5b75fc 100644
--- a/control/manager.hpp
+++ b/control/manager.hpp
@@ -36,9 +36,11 @@
          * _zoneLayouts data.
          *
          * @param[in] bus - The dbus object
+         * @param[in] events - The sd_event pointer
          * @param[in] mode - The control mode
          */
         Manager(sdbusplus::bus::bus& bus,
+                phosphor::fan::event::EventPtr& events,
                 Mode mode);
 
         /**
diff --git a/control/zone.cpp b/control/zone.cpp
index 1ca0b81..17e0089 100644
--- a/control/zone.cpp
+++ b/control/zone.cpp
@@ -13,6 +13,7 @@
  * 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>
@@ -27,18 +28,21 @@
 namespace control
 {
 
+using namespace std::chrono;
 using namespace phosphor::logging;
 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
                              Error::InternalFailure;
 
 Zone::Zone(Mode mode,
            sdbusplus::bus::bus& bus,
+           phosphor::fan::event::EventPtr& events,
            const ZoneDefinition& def) :
     _bus(bus),
     _fullSpeed(std::get<fullSpeedPos>(def)),
     _zoneNum(std::get<zoneNumPos>(def)),
     _defFloorSpeed(std::get<floorSpeedPos>(def)),
-    _defCeilingSpeed(std::get<fullSpeedPos>(def))
+    _defCeilingSpeed(std::get<fullSpeedPos>(def)),
+    _decTimer(events, [this](){ this->decTimerExpired(); })
 {
     auto& fanDefs = std::get<fanListPos>(def);
 
@@ -97,7 +101,13 @@
             std::get<actionPos>(event)(*this,
                                        std::get<groupPos>(event));
         }
-        //TODO openbmc/openbmc#1625 Start timer for fan speed decreases
+        // Start timer for fan speed decreases
+        if (!_decTimer.running())
+        {
+            //TODO Update time value to what's given in zones yaml
+            _decTimer.start(seconds(30),
+                            phosphor::fan::util::Timer::TimerType::repeating);
+        }
     }
 }
 
@@ -162,9 +172,12 @@
     {
         _decSpeedDelta = targetDelta;
     }
+}
 
-    //TODO openbmc/openbmc#1625 Set decrease target speed when timer expires
+void Zone::decTimerExpired()
+{
     // Only decrease speeds when no requested increases exist
+    //TODO Add increase timer not running (i.e. not in the middle of increasing)
     if (_incSpeedDelta == 0)
     {
         // Target speed can not go below the defined floor speed
@@ -181,7 +194,7 @@
     }
     // Clear decrease delta when timer expires
     _decSpeedDelta = 0;
-    //TODO openbmc/openbmc#1625 Restart decrease timer
+    // Decrease timer is restarted since its repeating
 }
 
 void Zone::getProperty(sdbusplus::bus::bus& bus,
diff --git a/control/zone.hpp b/control/zone.hpp
index f445472..30de150 100644
--- a/control/zone.hpp
+++ b/control/zone.hpp
@@ -5,6 +5,7 @@
 #include <sdbusplus/server.hpp>
 #include "fan.hpp"
 #include "types.hpp"
+#include "timer.hpp"
 
 namespace phosphor
 {
@@ -46,10 +47,12 @@
          *
          * @param[in] mode - mode of fan control
          * @param[in] bus - the dbus object
+         * @param[in] events - sd_event pointer
          * @param[in] def - the fan zone definition data
          */
         Zone(Mode mode,
              sdbusplus::bus::bus& bus,
+             phosphor::fan::event::EventPtr& events,
              const ZoneDefinition& def);
 
         /**
@@ -204,6 +207,12 @@
          */
         void requestSpeedDecrease(uint64_t targetDelta);
 
+        /**
+         * @brief Callback function for the decrease timer that processes any
+         * requested speed decreases if allowed
+         */
+        void decTimerExpired();
+
     private:
 
         /**
@@ -267,6 +276,11 @@
         uint64_t _decSpeedDelta = 0;
 
         /**
+         * The decrease timer object
+         */
+        phosphor::fan::util::Timer _decTimer;
+
+        /**
          * The vector of fans in this zone
          */
         std::vector<std::unique_ptr<Fan>> _fans;