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 /**
121  * @struct Interface Added
122  * @brief A match filter functor for Dbus interface added signals
123  *
124  * @tparam T - The type of the property value
125  * @tparam U - The type of the handler
126  */
127 template <typename T, typename U>
128 struct InterfaceAdded
129 {
130     InterfaceAdded() = delete;
131     ~InterfaceAdded() = default;
132     InterfaceAdded(const InterfaceAdded&) = default;
133     InterfaceAdded& operator=(const InterfaceAdded&) = default;
134     InterfaceAdded(InterfaceAdded&&) = default;
135     InterfaceAdded& operator=(InterfaceAdded&&) = default;
136     InterfaceAdded(const char* path,
137                    const char* iface,
138                    const char* property,
139                    U&& handler) :
140         _path(path),
141         _iface(iface),
142         _property(property),
143         _handler(std::forward<U>(handler)) { }
144 
145     /** @brief Run signal handler function
146      *
147      * Extract the property from the InterfacesAdded
148      * message and run the handler function.
149      */
150     void operator()(sdbusplus::bus::bus&,
151                     sdbusplus::message::message& msg,
152                     Zone& zone) const
153     {
154         std::map<std::string,
155                  std::map<std::string,
156                           sdbusplus::message::variant<T>>> intfProp;
157         sdbusplus::message::object_path op;
158 
159         msg.read(op);
160         auto objPath = static_cast<const std::string&>(op).c_str();
161         if (!objPath || strcmp(objPath, _path))
162         {
163             // Object path does not match this handler's path
164             return;
165         }
166 
167         msg.read(intfProp);
168         auto itIntf = intfProp.find(_iface);
169         if (itIntf == intfProp.cend())
170         {
171             // Interface not found on this handler's path
172             return;
173         }
174         auto itProp = itIntf->second.find(_property);
175         if (itProp == itIntf->second.cend())
176         {
177             // Property not found on this handler's path
178             return;
179         }
180 
181         _handler(zone, std::forward<T>(itProp->second.template get<T>()));
182     }
183 
184 private:
185     const char* _path;
186     const char* _iface;
187     const char* _property;
188     U _handler;
189 };
190 
191 /**
192  * @brief Used to process a Dbus interface added signal event
193  *
194  * @param[in] path - Object path
195  * @param[in] iface - Object interface
196  * @param[in] property - Object property
197  * @param[in] handler - Handler function to perform
198  *
199  * @tparam T - The type of the property
200  * @tparam U - The type of the handler
201  */
202 template <typename T, typename U>
203 auto objectSignal(const char* path,
204                   const char* iface,
205                   const char* property,
206                   U&& handler)
207 {
208     return InterfaceAdded<T, U>(path,
209                                 iface,
210                                 property,
211                                 std::forward<U>(handler));
212 }
213 
214 } // namespace control
215 } // namespace fan
216 } // namespace phosphor
217