diff options
-rw-r--r-- | control/functor.hpp | 109 | ||||
-rw-r--r-- | control/handlers.hpp | 35 | ||||
-rw-r--r-- | control/types.hpp | 18 | ||||
-rw-r--r-- | control/zone.cpp | 36 | ||||
-rw-r--r-- | control/zone.hpp | 50 |
5 files changed, 247 insertions, 1 deletions
diff --git a/control/functor.hpp b/control/functor.hpp new file mode 100644 index 0000000..f2f3a78 --- /dev/null +++ b/control/functor.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include "types.hpp" +#include <phosphor-logging/log.hpp> + +namespace phosphor +{ +namespace fan +{ +namespace control +{ +class Zone; + +using namespace phosphor::logging; + +/** + * @brief Create a handler function object + * + * @param[in] handler - The handler being created + * + * @return - The created handler function object + */ +template <typename T> +auto make_handler(T&& handler) +{ + return Handler(std::forward<T>(handler)); +} + +/** + * @struct Property Changed + * @brief A match filter functor for Dbus property value changed signals + * + * @tparam T - The type of the property value + * @tparam U - The type of the handler + */ +template <typename T, typename U> +struct PropertyChanged +{ + PropertyChanged() = delete; + ~PropertyChanged() = default; + PropertyChanged(const PropertyChanged&) = default; + PropertyChanged& operator=(const PropertyChanged&) = default; + PropertyChanged(PropertyChanged&&) = default; + PropertyChanged& operator=(PropertyChanged&&) = default; + PropertyChanged(const char* iface, + const char* property, + U&& handler) : + _iface(iface), + _property(property), + _handler(std::forward<U>(handler)) { } + + /** @brief Run signal handler function + * + * Extract the property from the PropertiesChanged + * message and run the handler function. + */ + void operator()(sdbusplus::bus::bus&, + sdbusplus::message::message& msg, + Zone& zone) const + { + std::map<std::string, sdbusplus::message::variant<T>> properties; + const char* iface = nullptr; + + msg.read(iface); + if (!iface || strcmp(iface, _iface)) + { + return; + } + + msg.read(properties); + auto it = properties.find(_property); + if (it == properties.cend()) + { + log<level::ERR>("Unable to find property on interface", + entry("PROPERTY=%s", _property), + entry("INTERFACE=%s", _iface)); + return; + } + + _handler(zone, std::forward<T>(it->second.template get<T>())); + } + +private: + const char* _iface; + const char* _property; + U _handler; +}; + +/** + * @brief Used to process a Dbus property changed signal event + * + * @param[in] iface - Sensor value interface + * @param[in] property - Sensor value property + * @param[in] handler - Handler function to perform + * + * @tparam T - The type of the property + * @tparam U - The type of the handler + */ +template <typename T, typename U> +auto propertySignal(const char* iface, + const char* property, + U&& handler) +{ + return PropertyChanged<T, U>(iface, property, std::forward<U>(handler)); +} + +} // namespace control +} // namespace fan +} // namespace phosphor diff --git a/control/handlers.hpp b/control/handlers.hpp new file mode 100644 index 0000000..0503c53 --- /dev/null +++ b/control/handlers.hpp @@ -0,0 +1,35 @@ +#pragma once + +namespace phosphor +{ +namespace fan +{ +namespace control +{ +namespace handler +{ + +/** + * @brief A handler function to set/update a property + * @details Sets or updates a property's value determined by a combination of + * an object's path and property names + * + * @param[in] path - Object's path name + * @param[in] property - Object's property name + * + * @return Lambda function + * A lambda function to set/update the property value + */ +template <typename T> +auto setProperty(const char* path, const char* property) +{ + return [=](auto& zone, T&& arg) + { + zone.setPropertyValue(path, property, std::forward<T>(arg)); + }; +} + +} // namespace handler +} // namespace control +} // namespace fan +} // namespace phosphor diff --git a/control/types.hpp b/control/types.hpp index e4c3725..bbbac61 100644 --- a/control/types.hpp +++ b/control/types.hpp @@ -10,6 +10,8 @@ namespace fan namespace control { +class Zone; + //Placeholder. Conditions are completely TBD. using Condition = bool; @@ -17,12 +19,26 @@ constexpr auto fanNamePos = 0; constexpr auto sensorListPos = 1; using FanDefinition = std::tuple<std::string, std::vector<std::string>>; +using Handler = std::function<void(sdbusplus::bus::bus&, + sdbusplus::message::message&, + Zone&)>; + +constexpr auto signaturePos = 0; +constexpr auto handlerObjPos = 1; +using PropertyChange = std::tuple<std::string, Handler>; +using SetSpeedEvent = std::vector<PropertyChange>; + +constexpr auto zoneObjPos = 0; +using SignalEvent = std::tuple<Zone*, Handler>; + constexpr auto zoneNumPos = 0; constexpr auto fullSpeedPos = 1; constexpr auto fanListPos = 2; +constexpr auto setSpeedEventsPos = 3; using ZoneDefinition = std::tuple<size_t, unsigned int, - std::vector<FanDefinition>>; + std::vector<FanDefinition>, + std::vector<SetSpeedEvent>>; constexpr auto conditionListPos = 0; constexpr auto zoneListPos = 1; diff --git a/control/zone.cpp b/control/zone.cpp index 1e50060..28b81f9 100644 --- a/control/zone.cpp +++ b/control/zone.cpp @@ -35,6 +35,22 @@ Zone::Zone(sdbusplus::bus::bus& bus, { _fans.emplace_back(std::make_unique<Fan>(bus, def)); } + + // Setup signal trigger for property changes
+ for (auto& event : std::get<setSpeedEventsPos>(def))
+ {
+ for (auto& prop : event)
+ {
+ _signalEvents.emplace_back(
+ std::make_unique<SignalEvent>(this,
+ std::get<handlerObjPos>(prop)
+ ));
+ _matches.emplace_back(bus,
+ std::get<signaturePos>(prop).c_str(),
+ signalHandler,
+ _signalEvents.back().get());
+ }
+ } } @@ -46,6 +62,26 @@ void Zone::setSpeed(uint64_t speed) } } +int Zone::signalHandler(sd_bus_message* msg, + void* data, + sd_bus_error* err) +{ + auto sdbpMsg = sdbusplus::message::message(msg); + auto& signalEvent = *static_cast<SignalEvent*>(data); + std::get<zoneObjPos>(signalEvent)->handleEvent( + sdbpMsg, + std::get<handlerObjPos>(signalEvent)); + return 0; +} + +void Zone::handleEvent(sdbusplus::message::message& msg, + const Handler& handler) +{ + // Handle the callback + handler(_bus, msg, *this); +} + + } } } diff --git a/control/zone.hpp b/control/zone.hpp index 985a46d..601c002 100644 --- a/control/zone.hpp +++ b/control/zone.hpp @@ -1,6 +1,7 @@ #pragma once #include <vector> #include <sdbusplus/bus.hpp> +#include <sdbusplus/server.hpp> #include "fan.hpp" #include "types.hpp" @@ -56,6 +57,20 @@ class Zone } } + /** + * @brief Sets a given object's property value + * + * @param[in] object - Name of the object containing the property + * @param[in] property - Property name + * @param[in] value - Property value + */ + void setPropertyValue(const char* object, + const char* property, + bool value) + { + _properties[object][property] = value; + }; + private: /** @@ -77,6 +92,41 @@ class Zone * The vector of fans in this zone */ std::vector<std::unique_ptr<Fan>> _fans; + + /** + * @brief Map of object property values + */ + std::map<std::string, std::map<std::string, bool>> _properties; + + /** + * @brief List of signal event arguments + */ + std::vector<std::unique_ptr<SignalEvent>> _signalEvents; + + /** + * @brief list of Dbus matches for callbacks + */ + std::vector<sdbusplus::server::match::match> _matches; + + /** + * @brief Dbus signal change handler + * + * @param[in] msg - Data associated with the subscribed signal + * @param[in] data - Pointer to the event sensor's data + * @param[in] err - Contains any sdbus error reference if occurred + */ + static int signalHandler(sd_bus_message* msg, + void* data, + sd_bus_error* err); + + /** + * @brief Envokes the assigned handler and action + * + * @param[in] msg - Expanded sdbusplus message data + * @param[in] eventData - The event's data + */ + void handleEvent(sdbusplus::message::message& msg, + const Handler& handler); }; } |