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 a service associated to a group
155          *
156          * @param[in] group - Group associated with service
157          * @param[in] name - Service name to remove
158          */
159         void removeService(const Group* group,
160                            const std::string& name);
161 
162         /**
163          * @brief Set or update a service name owner in use
164          *
165          * @param[in] group - Group associated with service
166          * @param[in] name - Service name
167          * @param[in] hasOwner - Whether the service is owned or not
168          */
169         void setServiceOwner(const Group* group,
170                              const std::string& name,
171                              const bool hasOwner);
172 
173         /**
174          * @brief Set or update all services for a group
175          *
176          * @param[in] group - Group to get service names for
177          */
178         void setServices(const Group* group);
179 
180         /**
181          * @brief Get the group's list of service names
182          *
183          * @param[in] group - Group to get service names for
184          *
185          * @return - The list of service names
186          */
187         inline auto getGroupServices(const Group* group)
188         {
189             return _services.at(*group);
190         }
191 
192         /**
193          * @brief Initialize a set speed event properties and actions
194          *
195          * @param[in] event - Set speed event
196          */
197         void initEvent(const SetSpeedEvent& event);
198 
199         /**
200          * @brief Removes all the set speed event properties and actions
201          *
202          * @param[in] event - Set speed event
203          */
204         void removeEvent(const SetSpeedEvent& event);
205 
206         /**
207          * @brief Get the default floor speed
208          *
209          * @return - The defined default floor speed
210          */
211         inline auto getDefFloor()
212         {
213             return _defFloorSpeed;
214         };
215 
216         /**
217          * @brief Get the ceiling speed
218          *
219          * @return - The current ceiling speed
220          */
221         inline auto& getCeiling() const
222         {
223             return _ceilingSpeed;
224         };
225 
226         /**
227          * @brief Set the ceiling speed to the given speed
228          *
229          * @param[in] speed - Speed to set the ceiling to
230          */
231         inline void setCeiling(uint64_t speed)
232         {
233             _ceilingSpeed = speed;
234         };
235 
236         /**
237          * @brief Swaps the ceiling key value with what's given and
238          * returns the value that was swapped.
239          *
240          * @param[in] keyValue - New ceiling key value
241          *
242          * @return - Ceiling key value prior to swapping
243          */
244         inline auto swapCeilingKeyValue(int64_t keyValue)
245         {
246             std::swap(_ceilingKeyValue, keyValue);
247             return keyValue;
248         };
249 
250         /**
251          * @brief Get the increase speed delta
252          *
253          * @return - The current increase speed delta
254          */
255         inline auto& getIncSpeedDelta() const
256         {
257             return _incSpeedDelta;
258         };
259 
260         /**
261          * @brief Get the decrease speed delta
262          *
263          * @return - The current decrease speed delta
264          */
265         inline auto& getDecSpeedDelta() const
266         {
267             return _decSpeedDelta;
268         };
269 
270         /**
271          * @brief Set the floor speed to the given speed and increase target
272          * speed to the floor when target is below floor where floor changes
273          * are allowed.
274          *
275          * @param[in] speed - Speed to set the floor to
276          */
277         void setFloor(uint64_t speed);
278 
279         /**
280          * @brief Set the requested speed base to be used as the speed to
281          * base a new requested speed target from
282          *
283          * @param[in] speedBase - Base speed value to use
284          */
285         inline void setRequestSpeedBase(uint64_t speedBase)
286         {
287             _requestSpeedBase = speedBase;
288         };
289 
290         /**
291          * @brief Calculate the requested target speed from the given delta
292          * and increase the fan speeds, not going above the ceiling.
293          *
294          * @param[in] targetDelta - The delta to increase the target speed by
295          */
296         void requestSpeedIncrease(uint64_t targetDelta);
297 
298         /**
299          * @brief Calculate the requested target speed from the given delta
300          * and increase the fan speeds, not going above the ceiling.
301          *
302          * @param[in] targetDelta - The delta to increase the target speed by
303          */
304         void requestSpeedDecrease(uint64_t targetDelta);
305 
306         /**
307          * @brief Callback function for the increase timer that delays
308          * processing of requested speed increases while fans are increasing
309          */
310         void incTimerExpired();
311 
312         /**
313          * @brief Callback function for the decrease timer that processes any
314          * requested speed decreases if allowed
315          */
316         void decTimerExpired();
317 
318         /**
319          * @brief Get the event pointer used with this zone's timers
320          *
321          * @return - The Dbus event pointer for timers
322          */
323         inline auto& getEventPtr()
324         {
325             return _sdEvents;
326         }
327 
328         /**
329          * @brief Get the list of timer events
330          *
331          * @return - List of timer events
332          */
333         inline auto& getTimerEvents()
334         {
335             return _timerEvents;
336         }
337 
338         /**
339          * @brief Find the first instance of a timer event
340          *
341          * @param[in] eventGroup - Group associated with a timer
342          * @param[in] eventActions - List of actions associated with a timer
343          *
344          * @return - Iterator to the timer event
345          */
346         std::vector<TimerEvent>::iterator findTimer(
347                 const Group& eventGroup,
348                 const std::vector<Action>& eventActions);
349 
350         /**
351          * @brief Add a timer to the list of timer based events
352          *
353          * @param[in] data - Event data for timer
354          * @param[in] timer - Timer to be added
355          */
356         inline void addTimer(
357                 std::unique_ptr<EventData>&& data,
358                 std::unique_ptr<phosphor::fan::util::Timer>&& timer)
359         {
360             _timerEvents.emplace_back(std::move(data), std::move(timer));
361         };
362 
363         /**
364          * @brief Remove the given timer event
365          *
366          * @param[in] teIter - Iterator pointing to the timer event to remove
367          */
368         inline void removeTimer(std::vector<TimerEvent>::iterator& teIter)
369         {
370             assert(teIter != std::end(_timerEvents));
371             std::get<timerEventDataPos>(*teIter).reset();
372             std::get<timerTimerPos>(*teIter).reset();
373             _timerEvents.erase(teIter);
374         }
375 
376         /**
377          * @brief Callback function for event timers that processes the given
378          * actions for a group
379          *
380          * @param[in] eventGroup - Group to process actions on
381          * @param[in] eventActions - List of event actions to run
382          */
383         void timerExpired(Group eventGroup, std::vector<Action> eventActions);
384 
385     private:
386 
387         /**
388          * The dbus object
389          */
390         sdbusplus::bus::bus& _bus;
391 
392         /**
393          * Full speed for the zone
394          */
395         const uint64_t _fullSpeed;
396 
397         /**
398          * The zone number
399          */
400         const size_t _zoneNum;
401 
402         /**
403          * The default floor speed for the zone
404          */
405         const uint64_t _defFloorSpeed;
406 
407         /**
408          * The default ceiling speed for the zone
409          */
410         const uint64_t _defCeilingSpeed;
411 
412         /**
413          * The floor speed to not go below
414          */
415         uint64_t _floorSpeed = _defFloorSpeed;
416 
417         /**
418          * The ceiling speed to not go above
419          */
420         uint64_t _ceilingSpeed = _defCeilingSpeed;
421 
422         /**
423          * The previous sensor value for calculating the ceiling
424          */
425         int64_t _ceilingKeyValue = 0;
426 
427         /**
428          * Automatic fan control active state
429          */
430         bool _isActive = true;
431 
432         /**
433          * Target speed for this zone
434          */
435         uint64_t _targetSpeed = _fullSpeed;
436 
437         /**
438          * Speed increase delta
439          */
440         uint64_t _incSpeedDelta = 0;
441 
442         /**
443          * Speed decrease delta
444          */
445         uint64_t _decSpeedDelta = 0;
446 
447         /**
448          * Requested speed base
449          */
450         uint64_t _requestSpeedBase = 0;
451 
452         /**
453          * Speed increase delay in seconds
454          */
455         std::chrono::seconds _incDelay;
456 
457         /**
458          * Speed decrease interval in seconds
459          */
460         std::chrono::seconds _decInterval;
461 
462         /**
463          * The increase timer object
464          */
465         phosphor::fan::util::Timer _incTimer;
466 
467         /**
468          * The decrease timer object
469          */
470         phosphor::fan::util::Timer _decTimer;
471 
472         /**
473          * Dbus event used on set speed event timers
474          */
475         phosphor::fan::event::EventPtr& _sdEvents;
476 
477         /**
478          * The vector of fans in this zone
479          */
480         std::vector<std::unique_ptr<Fan>> _fans;
481 
482         /**
483          * @brief Map of object property values
484          */
485         std::map<std::string,
486                  std::map<std::string,
487                           std::map<std::string,
488                                    PropertyVariantType>>> _properties;
489 
490         /**
491          * @brief Map of active fan control allowed by groups
492          */
493         std::map<const Group, bool> _active;
494 
495         /**
496          * @brief Map of floor change allowed by groups
497          */
498         std::map<const Group, bool> _floorChange;
499 
500         /**
501          * @brief Map of groups controlling decreases allowed
502          */
503         std::map<const Group, bool> _decAllowed;
504 
505         /**
506          * @brief Map of group service names
507          */
508         std::map<const Group, std::vector<Service>> _services;
509 
510         /**
511          * @brief List of signal event arguments and Dbus matches for callbacks
512          */
513         std::vector<SignalEvent> _signalEvents;
514 
515         /**
516          * @brief List of timers for events
517          */
518         std::vector<TimerEvent> _timerEvents;
519 
520         /**
521          * @brief Get the request speed base if defined, otherwise the
522          * the current target speed is returned
523          *
524          * @return - The request speed base or current target speed
525          */
526         inline auto getRequestSpeedBase() const
527         {
528             return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed;
529         };
530 
531         /**
532          * @brief Dbus signal change callback handler
533          *
534          * @param[in] msg - Expanded sdbusplus message data
535          * @param[in] eventData - The single event's data
536          */
537         void handleEvent(sdbusplus::message::message& msg,
538                          const EventData* eventData);
539 };
540 
541 }
542 }
543 }
544