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