control: Handle adding timers and when they expire
Timers are added to the manager object with a package of data that's
used when the timer expires and runs a set of actions. Each timer added
creates a new timer instance and `oneshot` timers are removed when they
expire.
Change-Id: I1c47878fd3f68a1121b0fd0dfdfe3e66f9ff783f
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/actions/action.hpp b/control/json/actions/action.hpp
index 1525175..06759cc 100644
--- a/control/json/actions/action.hpp
+++ b/control/json/actions/action.hpp
@@ -15,9 +15,9 @@
*/
#pragma once
+#include "../zone.hpp"
#include "config_base.hpp"
#include "group.hpp"
-#include "zone.hpp"
#include <fmt/format.h>
diff --git a/control/json/manager.cpp b/control/json/manager.cpp
index 3508307..a072f49 100644
--- a/control/json/manager.cpp
+++ b/control/json/manager.cpp
@@ -17,7 +17,9 @@
#include "manager.hpp"
+#include "action.hpp"
#include "fan.hpp"
+#include "group.hpp"
#include "json_config.hpp"
#include "profile.hpp"
#include "zone.hpp"
@@ -25,9 +27,16 @@
#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
#include <sdeventplus/event.hpp>
+#include <sdeventplus/utility/timer.hpp>
#include <algorithm>
+#include <chrono>
#include <filesystem>
+#include <functional>
+#include <map>
+#include <memory>
+#include <tuple>
+#include <utility>
#include <vector>
namespace phosphor::fan::control::json
@@ -106,6 +115,55 @@
return false;
}
+void Manager::addTimer(const TimerType type,
+ const std::chrono::microseconds interval,
+ std::unique_ptr<TimerPkg> pkg)
+{
+ auto dataPtr =
+ std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
+ Timer timer(_event,
+ std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
+ if (type == TimerType::repeating)
+ {
+ timer.restart(interval);
+ }
+ else if (type == TimerType::oneshot)
+ {
+ timer.restartOnce(interval);
+ }
+ else
+ {
+ throw std::invalid_argument("Invalid Timer Type");
+ }
+ _timers.emplace_back(std::move(dataPtr), std::move(timer));
+}
+
+void Manager::timerExpired(TimerData& data)
+{
+ auto& actions =
+ std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
+ // Perform the actions in the timer data
+ std::for_each(actions.begin(), actions.end(),
+ [zone = std::ref(std::get<Zone&>(data.second)),
+ group = std::cref(std::get<const Group&>(data.second))](
+ auto& action) { action->run(zone, group); });
+
+ // Remove oneshot timers after they expired
+ if (data.first == TimerType::oneshot)
+ {
+ auto itTimer = std::find_if(
+ _timers.begin(), _timers.end(), [&data](const auto& timer) {
+ return (data.first == timer.first->first &&
+ (std::get<std::string>(data.second) ==
+ std::get<std::string>(timer.first->second)));
+ });
+ if (itTimer != std::end(_timers))
+ {
+ _timers.erase(itTimer);
+ }
+ }
+}
+
unsigned int Manager::getPowerOnDelay()
{
auto powerOnDelay = 0;
diff --git a/control/json/manager.hpp b/control/json/manager.hpp
index eeedfd3..c2a0904 100644
--- a/control/json/manager.hpp
+++ b/control/json/manager.hpp
@@ -15,6 +15,8 @@
*/
#pragma once
+#include "action.hpp"
+#include "group.hpp"
#include "json_config.hpp"
#include "profile.hpp"
#include "zone.hpp"
@@ -22,6 +24,15 @@
#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
#include <sdeventplus/event.hpp>
+#include <sdeventplus/utility/timer.hpp>
+
+#include <chrono>
+#include <map>
+#include <memory>
+#include <optional>
+#include <tuple>
+#include <utility>
+#include <vector>
namespace phosphor::fan::control::json
{
@@ -40,6 +51,33 @@
*/
using configKey = std::pair<std::string, std::vector<std::string>>;
+/* Type of timers supported */
+enum class TimerType
+{
+ oneshot,
+ repeating,
+};
+/**
+ * Package of data required when a timer expires
+ * Tuple constructed of:
+ * std::string = Timer package unique identifier
+ * Zone = Zone object to run the actions against
+ * Group = Group of dbus objects for the actions
+ * std::vector<std::unique_ptr<ActionBase>> = List of pointers to actions
+ * that run when the timer expires
+ */
+using TimerPkg = std::tuple<std::string, Zone&, const Group&,
+ std::vector<std::unique_ptr<ActionBase>>&>;
+/**
+ * Data associated with a running timer that's used when it expires
+ * Pair constructed of:
+ * TimerType = Type of timer to manage expired timer instances
+ * TimerPkg = Package of data required when the timer expires
+ */
+using TimerData = std::pair<TimerType, TimerPkg>;
+/* Dbus event timer */
+using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
+
/**
* @class Manager - Represents the fan control manager's configuration
*
@@ -162,6 +200,24 @@
};
/**
+ * @brief Add a dbus timer
+ *
+ * @param[in] type - Type of timer
+ * @param[in] interval - Timer interval in microseconds
+ * @param[in] pkg - Packaged data for when timer expires
+ */
+ void addTimer(const TimerType type,
+ const std::chrono::microseconds interval,
+ std::unique_ptr<TimerPkg> pkg);
+
+ /**
+ * @brief Callback when a timer expires
+ *
+ * @param[in] data - Data to be used when the timer expired
+ */
+ void timerExpired(TimerData& data);
+
+ /**
* @brief Get the configured power on delay(OPTIONAL)
*
* @return Power on delay in seconds
@@ -203,6 +259,9 @@
std::map<std::string, std::map<std::string, PropertyVariantType>>>
_objects;
+ /* List of timers and their data to be processed when expired */
+ std::vector<std::pair<std::unique_ptr<TimerData>, Timer>> _timers;
+
/* List of zones configured */
std::map<configKey, std::unique_ptr<Zone>> _zones;