1 #pragma once
2 #include <chrono>
3 #include <vector>
4 #include <cassert>
5 #include <algorithm>
6 #include <sdbusplus/bus.hpp>
7 #include "fan.hpp"
8 #include "types.hpp"
9 #include "timer.hpp"
10 
11 namespace phosphor
12 {
13 namespace fan
14 {
15 namespace control
16 {
17 
18 /**
19  * The mode fan control will run in:
20  *   - init - only do the initialization steps
21  *   - control - run normal control algorithms
22  */
23 enum class Mode
24 {
25     init,
26     control
27 };
28 
29 /**
30  * @class Represents a fan control zone, which is a group of fans
31  * that behave the same.
32  */
33 class Zone
34 {
35     public:
36 
37         Zone() = delete;
38         Zone(const Zone&) = delete;
39         Zone(Zone&&) = delete;
40         Zone& operator=(const Zone&) = delete;
41         Zone& operator=(Zone&&) = delete;
42         ~Zone() = default;
43 
44         /**
45          * Constructor
46          * Creates the appropriate fan objects based on
47          * the zone definition data passed in.
48          *
49          * @param[in] mode - mode of fan control
50          * @param[in] bus - the dbus object
51          * @param[in] events - sd_event pointer
52          * @param[in] def - the fan zone definition data
53          */
54         Zone(Mode mode,
55              sdbusplus::bus::bus& bus,
56              phosphor::fan::event::EventPtr& events,
57              const ZoneDefinition& def);
58 
59         /**
60          * Sets all fans in the zone to the speed
61          * passed in when the zone is active
62          *
63          * @param[in] speed - the fan speed
64          */
65         void setSpeed(uint64_t speed);
66 
67         /**
68          * Sets the zone to full speed regardless of zone's active state
69          */
70         void setFullSpeed();
71 
72         /**
73          * @brief Sets the automatic fan control allowed active state
74          *
75          * @param[in] group - A group that affects the active state
76          * @param[in] isActiveAllow - Active state according to group
77          */
78         void setActiveAllow(const Group* group, bool isActiveAllow);
79 
80         /**
81          * @brief Sets the floor change allowed state
82          *
83          * @param[in] group - A group that affects floor changes
84          * @param[in] isAllow - Allow state according to group
85          */
86         inline void setFloorChangeAllow(const Group* group, bool isAllow)
87         {
88             _floorChange[*(group)] = isAllow;
89         }
90 
91         /**
92          * @brief Sets the decrease allowed state of a group
93          *
94          * @param[in] group - A group that affects speed decreases
95          * @param[in] isAllow - Allow state according to group
96          */
97         inline void setDecreaseAllow(const Group* group, bool isAllow)
98         {
99             _decAllowed[*(group)] = isAllow;
100         }
101 
102         /**
103          * @brief Sets a given object's property value
104          *
105          * @param[in] object - Name of the object containing the property
106          * @param[in] interface - Interface name containing the property
107          * @param[in] property - Property name
108          * @param[in] value - Property value
109          */
110         template <typename T>
111         void setPropertyValue(const char* object,
112                               const char* interface,
113                               const char* property,
114                               T value)
115         {
116             _properties[object][interface][property] = value;
117         };
118 
119         /**
120          * @brief Get the value of an object's property
121          *
122          * @param[in] object - Name of the object containing the property
123          * @param[in] interface - Interface name containing the property
124          * @param[in] property - Property name
125          *
126          * @return - The property value
127          */
128         template <typename T>
129         inline auto getPropertyValue(const std::string& object,
130                                      const std::string& interface,
131                                      const std::string& property)
132         {
133             return sdbusplus::message::variant_ns::get<T>(
134                     _properties.at(object).at(interface).at(property));
135         };
136 
137         /**
138          * @brief Get the object's property variant
139          *
140          * @param[in] object - Name of the object containing the property
141          * @param[in] interface - Interface name containing the property
142          * @param[in] property - Property name
143          *
144          * @return - The property variant
145          */
146         inline auto getPropValueVariant(const std::string& object,
147                                         const std::string& interface,
148                                         const std::string& property)
149         {
150             return _properties.at(object).at(interface).at(property);
151         };
152 
153         /**
154          * @brief Remove an object's interface
155          *
156          * @param[in] object - Name of the object with the interface
157          * @param[in] interface - Interface name to remove
158          */
159         inline void removeObjectInterface(const char* object,
160                                           const char* interface)
161         {
162             auto it = _properties.find(object);
163             if (it != std::end(_properties))
164             {
165                 _properties[object].erase(interface);
166             }
167         }
168 
169         /**
170          * @brief Remove a service associated to a group
171          *
172          * @param[in] group - Group associated with service
173          * @param[in] name - Service name to remove
174          */
175         void removeService(const Group* group,
176                            const std::string& name);
177 
178         /**
179          * @brief Set or update a service name owner in use
180          *
181          * @param[in] group - Group associated with service
182          * @param[in] name - Service name
183          * @param[in] hasOwner - Whether the service is owned or not
184          */
185         void setServiceOwner(const Group* group,
186                              const std::string& name,
187                              const bool hasOwner);
188 
189         /**
190          * @brief Set or update all services for a group
191          *
192          * @param[in] group - Group to get service names for
193          */
194         void setServices(const Group* group);
195 
196         /**
197          * @brief Get the group's list of service names
198          *
199          * @param[in] group - Group to get service names for
200          *
201          * @return - The list of service names
202          */
203         inline auto getGroupServices(const Group* group)
204         {
205             return _services.at(*group);
206         }
207 
208         /**
209          * @brief Initialize a set speed event properties and actions
210          *
211          * @param[in] event - Set speed event
212          */
213         void initEvent(const SetSpeedEvent& event);
214 
215         /**
216          * @brief Removes all the set speed event properties and actions
217          *
218          * @param[in] event - Set speed event
219          */
220         void removeEvent(const SetSpeedEvent& event);
221 
222         /**
223          * @brief Get the default floor speed
224          *
225          * @return - The defined default floor speed
226          */
227         inline auto getDefFloor()
228         {
229             return _defFloorSpeed;
230         };
231 
232         /**
233          * @brief Get the ceiling speed
234          *
235          * @return - The current ceiling speed
236          */
237         inline auto& getCeiling() const
238         {
239             return _ceilingSpeed;
240         };
241 
242         /**
243          * @brief Set the ceiling speed to the given speed
244          *
245          * @param[in] speed - Speed to set the ceiling to
246          */
247         inline void setCeiling(uint64_t speed)
248         {
249             _ceilingSpeed = speed;
250         };
251 
252         /**
253          * @brief Swaps the ceiling key value with what's given and
254          * returns the value that was swapped.
255          *
256          * @param[in] keyValue - New ceiling key value
257          *
258          * @return - Ceiling key value prior to swapping
259          */
260         inline auto swapCeilingKeyValue(int64_t keyValue)
261         {
262             std::swap(_ceilingKeyValue, keyValue);
263             return keyValue;
264         };
265 
266         /**
267          * @brief Get the increase speed delta
268          *
269          * @return - The current increase speed delta
270          */
271         inline auto& getIncSpeedDelta() const
272         {
273             return _incSpeedDelta;
274         };
275 
276         /**
277          * @brief Get the decrease speed delta
278          *
279          * @return - The current decrease speed delta
280          */
281         inline auto& getDecSpeedDelta() const
282         {
283             return _decSpeedDelta;
284         };
285 
286         /**
287          * @brief Set the floor speed to the given speed and increase target
288          * speed to the floor when target is below floor where floor changes
289          * are allowed.
290          *
291          * @param[in] speed - Speed to set the floor to
292          */
293         void setFloor(uint64_t speed);
294 
295         /**
296          * @brief Set the requested speed base to be used as the speed to
297          * base a new requested speed target from
298          *
299          * @param[in] speedBase - Base speed value to use
300          */
301         inline void setRequestSpeedBase(uint64_t speedBase)
302         {
303             _requestSpeedBase = speedBase;
304         };
305 
306         /**
307          * @brief Calculate the requested target speed from the given delta
308          * and increase the fan speeds, not going above the ceiling.
309          *
310          * @param[in] targetDelta - The delta to increase the target speed by
311          */
312         void requestSpeedIncrease(uint64_t targetDelta);
313 
314         /**
315          * @brief Calculate the requested target speed from the given delta
316          * and increase the fan speeds, not going above the ceiling.
317          *
318          * @param[in] targetDelta - The delta to increase the target speed by
319          */
320         void requestSpeedDecrease(uint64_t targetDelta);
321 
322         /**
323          * @brief Callback function for the increase timer that delays
324          * processing of requested speed increases while fans are increasing
325          */
326         void incTimerExpired();
327 
328         /**
329          * @brief Callback function for the decrease timer that processes any
330          * requested speed decreases if allowed
331          */
332         void decTimerExpired();
333 
334         /**
335          * @brief Get the event pointer used with this zone's timers
336          *
337          * @return - The Dbus event pointer for timers
338          */
339         inline auto& getEventPtr()
340         {
341             return _sdEvents;
342         }
343 
344         /**
345          * @brief Get the list of timer events
346          *
347          * @return - List of timer events
348          */
349         inline auto& getTimerEvents()
350         {
351             return _timerEvents;
352         }
353 
354         /**
355          * @brief Find the first instance of a timer event
356          *
357          * @param[in] eventGroup - Group associated with a timer
358          * @param[in] eventActions - List of actions associated with a timer
359          *
360          * @return - Iterator to the timer event
361          */
362         std::vector<TimerEvent>::iterator findTimer(
363                 const Group& eventGroup,
364                 const std::vector<Action>& eventActions);
365 
366         /**
367          * @brief Add a timer to the list of timer based events
368          *
369          * @param[in] data - Event data for timer
370          * @param[in] timer - Timer to be added
371          */
372         inline void addTimer(
373                 std::unique_ptr<EventData>&& data,
374                 std::unique_ptr<phosphor::fan::util::Timer>&& timer)
375         {
376             _timerEvents.emplace_back(std::move(data), std::move(timer));
377         };
378 
379         /**
380          * @brief Remove the given timer event
381          *
382          * @param[in] teIter - Iterator pointing to the timer event to remove
383          */
384         inline void removeTimer(std::vector<TimerEvent>::iterator& teIter)
385         {
386             assert(teIter != std::end(_timerEvents));
387             std::get<timerEventDataPos>(*teIter).reset();
388             std::get<timerTimerPos>(*teIter).reset();
389             _timerEvents.erase(teIter);
390         }
391 
392         /**
393          * @brief Callback function for event timers that processes the given
394          * actions for a group
395          *
396          * @param[in] eventGroup - Group to process actions on
397          * @param[in] eventActions - List of event actions to run
398          */
399         void timerExpired(Group eventGroup, std::vector<Action> eventActions);
400 
401         /**
402          * @brief Get the service for a given path and interface from cached
403          * dataset and add a service that's not found
404          *
405          * @param[in] path - Path to get service for
406          * @param[in] intf - Interface to get service for
407          *
408          * @return - The service name
409          */
410         const std::string& getService(const std::string& path,
411                                       const std::string& intf);
412 
413         /**
414          * @brief Add a set of services for a path and interface
415          * by retrieving all the path subtrees to the given depth
416          * from root for the interface
417          *
418          * @param[in] path - Path to add services for
419          * @param[in] intf - Interface to add services for
420          * @param[in] depth - Depth of tree traversal from root path
421          *
422          * @return - The associated service to the given path and interface
423          * or empty string for no service found
424          */
425         const std::string& addServices(const std::string& path,
426                                        const std::string& intf,
427                                        int32_t depth);
428 
429     private:
430 
431         /**
432          * The dbus object
433          */
434         sdbusplus::bus::bus& _bus;
435 
436         /**
437          * Full speed for the zone
438          */
439         const uint64_t _fullSpeed;
440 
441         /**
442          * The zone number
443          */
444         const size_t _zoneNum;
445 
446         /**
447          * The default floor speed for the zone
448          */
449         const uint64_t _defFloorSpeed;
450 
451         /**
452          * The default ceiling speed for the zone
453          */
454         const uint64_t _defCeilingSpeed;
455 
456         /**
457          * The floor speed to not go below
458          */
459         uint64_t _floorSpeed = _defFloorSpeed;
460 
461         /**
462          * The ceiling speed to not go above
463          */
464         uint64_t _ceilingSpeed = _defCeilingSpeed;
465 
466         /**
467          * The previous sensor value for calculating the ceiling
468          */
469         int64_t _ceilingKeyValue = 0;
470 
471         /**
472          * Automatic fan control active state
473          */
474         bool _isActive = true;
475 
476         /**
477          * Target speed for this zone
478          */
479         uint64_t _targetSpeed = _fullSpeed;
480 
481         /**
482          * Speed increase delta
483          */
484         uint64_t _incSpeedDelta = 0;
485 
486         /**
487          * Speed decrease delta
488          */
489         uint64_t _decSpeedDelta = 0;
490 
491         /**
492          * Requested speed base
493          */
494         uint64_t _requestSpeedBase = 0;
495 
496         /**
497          * Speed increase delay in seconds
498          */
499         std::chrono::seconds _incDelay;
500 
501         /**
502          * Speed decrease interval in seconds
503          */
504         std::chrono::seconds _decInterval;
505 
506         /**
507          * The increase timer object
508          */
509         phosphor::fan::util::Timer _incTimer;
510 
511         /**
512          * The decrease timer object
513          */
514         phosphor::fan::util::Timer _decTimer;
515 
516         /**
517          * Dbus event used on set speed event timers
518          */
519         phosphor::fan::event::EventPtr& _sdEvents;
520 
521         /**
522          * The vector of fans in this zone
523          */
524         std::vector<std::unique_ptr<Fan>> _fans;
525 
526         /**
527          * @brief Map of object property values
528          */
529         std::map<std::string,
530                  std::map<std::string,
531                           std::map<std::string,
532                                    PropertyVariantType>>> _properties;
533 
534         /**
535          * @brief Map of active fan control allowed by groups
536          */
537         std::map<const Group, bool> _active;
538 
539         /**
540          * @brief Map of floor change allowed by groups
541          */
542         std::map<const Group, bool> _floorChange;
543 
544         /**
545          * @brief Map of groups controlling decreases allowed
546          */
547         std::map<const Group, bool> _decAllowed;
548 
549         /**
550          * @brief Map of group service names
551          */
552         std::map<const Group, std::vector<Service>> _services;
553 
554         /**
555          * @brief Map tree of paths to services of interfaces
556          */
557         std::map<std::string,
558                 std::map<std::string,
559                 std::vector<std::string>>> _servTree;
560 
561         /**
562          * @brief List of signal event arguments and Dbus matches for callbacks
563          */
564         std::vector<SignalEvent> _signalEvents;
565 
566         /**
567          * @brief List of timers for events
568          */
569         std::vector<TimerEvent> _timerEvents;
570 
571         /**
572          * @brief Get the request speed base if defined, otherwise the
573          * the current target speed is returned
574          *
575          * @return - The request speed base or current target speed
576          */
577         inline auto getRequestSpeedBase() const
578         {
579             return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed;
580         };
581 
582         /**
583          * @brief Dbus signal change callback handler
584          *
585          * @param[in] msg - Expanded sdbusplus message data
586          * @param[in] eventData - The single event's data
587          */
588         void handleEvent(sdbusplus::message::message& msg,
589                          const EventData* eventData);
590 };
591 
592 }
593 }
594 }
595