1 #pragma once
2 
3 #include "types.hpp"
4 #include <phosphor-logging/log.hpp>
5 
6 namespace phosphor
7 {
8 namespace fan
9 {
10 namespace control
11 {
12 class Zone;
13 
14 using namespace phosphor::logging;
15 
16 /**
17  * @brief Create a handler function object
18  *
19  * @param[in] handler - The handler being created
20  *
21  * @return - The created handler function object
22  */
23 template <typename T>
24 auto make_handler(T&& handler)
25 {
26     return Handler(std::forward<T>(handler));
27 }
28 
29 /**
30  * @brief Create an action function object
31  *
32  * @param[in] action - The action being created
33  *
34  * @return - The created action function object
35  */
36 template <typename T>
37 auto make_action(T&& action)
38 {
39     return Action(std::forward<T>(action));
40 }
41 
42 /**
43  * @struct Property Changed
44  * @brief A match filter functor for Dbus property value changed signals
45  *
46  * @tparam T - The type of the property value
47  * @tparam U - The type of the handler
48  */
49 template <typename T, typename U>
50 struct PropertyChanged
51 {
52     PropertyChanged() = delete;
53     ~PropertyChanged() = default;
54     PropertyChanged(const PropertyChanged&) = default;
55     PropertyChanged& operator=(const PropertyChanged&) = default;
56     PropertyChanged(PropertyChanged&&) = default;
57     PropertyChanged& operator=(PropertyChanged&&) = default;
58     PropertyChanged(const char* iface,
59                     const char* property,
60                     U&& handler) :
61         _iface(iface),
62         _property(property),
63         _handler(std::forward<U>(handler)) { }
64 
65     /** @brief Run signal handler function
66      *
67      * Extract the property from the PropertiesChanged
68      * message and run the handler function.
69      */
70     void operator()(sdbusplus::bus::bus&,
71                     sdbusplus::message::message& msg,
72                     Zone& zone) const
73     {
74         std::map<std::string, sdbusplus::message::variant<T>> properties;
75         const char* iface = nullptr;
76 
77         msg.read(iface);
78         if (!iface || strcmp(iface, _iface))
79         {
80             return;
81         }
82 
83         msg.read(properties);
84         auto it = properties.find(_property);
85         if (it == properties.cend())
86         {
87             log<level::ERR>("Unable to find property on interface",
88                             entry("PROPERTY=%s", _property),
89                             entry("INTERFACE=%s", _iface));
90             return;
91         }
92 
93         _handler(zone, std::forward<T>(it->second.template get<T>()));
94     }
95 
96 private:
97     const char* _iface;
98     const char* _property;
99     U _handler;
100 };
101 
102 /**
103  * @brief Used to process a Dbus property changed signal event
104  *
105  * @param[in] iface - Sensor value interface
106  * @param[in] property - Sensor value property
107  * @param[in] handler - Handler function to perform
108  *
109  * @tparam T - The type of the property
110  * @tparam U - The type of the handler
111  */
112 template <typename T, typename U>
113 auto propertySignal(const char* iface,
114                     const char* property,
115                     U&& handler)
116 {
117     return PropertyChanged<T, U>(iface, property, std::forward<U>(handler));
118 }
119 
120 } // namespace control
121 } // namespace fan
122 } // namespace phosphor
123