xref: /openbmc/phosphor-fan-presence/control/zone.hpp (revision 8fd879fb7bb9ed34fe69581dc714b4158046519f)
1 #pragma once
2 #include <algorithm>
3 #include <cassert>
4 #include <chrono>
5 #include <sdbusplus/bus.hpp>
6 #include <sdeventplus/event.hpp>
7 #include <vector>
8 #include "fan.hpp"
9 #include "types.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] event - Event loop reference
52          * @param[in] def - the fan zone definition data
53          */
54         Zone(Mode mode,
55              sdbusplus::bus::bus& bus,
56              const sdeventplus::Event& event,
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 loop used with this zone's timers
336          *
337          * @return - The event loop for timers
338          */
339         inline auto& getEventLoop()
340         {
341             return _eventLoop;
342         }
343 
344         /**
345          * @brief Get the list of signal events
346          *
347          * @return - List of signal events
348          */
349         inline auto& getSignalEvents()
350         {
351             return _signalEvents;
352         }
353 
354         /**
355          * @brief Find the first instance of a signal event
356          *
357          * @param[in] signal - Event signal to find
358          * @param[in] eGroup - Group associated with the signal
359          * @param[in] eActions - List of actions associated with the signal
360          *
361          * @return - Iterator to the stored signal event
362          */
363         std::vector<SignalEvent>::iterator findSignal(
364             const Signal& signal,
365             const Group& eGroup,
366             const std::vector<Action>& eActions);
367 
368         /**
369          * @brief Remove the given signal event
370          *
371          * @param[in] seIter - Iterator pointing to the signal event to remove
372          */
373         inline void removeSignal(std::vector<SignalEvent>::iterator& seIter)
374         {
375             assert(seIter != std::end(_signalEvents));
376             std::get<signalEventDataPos>(*seIter).reset();
377             if (std::get<signalMatchPos>(*seIter) != nullptr)
378             {
379                 std::get<signalMatchPos>(*seIter).reset();
380             }
381             _signalEvents.erase(seIter);
382         }
383 
384         /**
385          * @brief Get the list of timer events
386          *
387          * @return - List of timer events
388          */
389         inline auto& getTimerEvents()
390         {
391             return _timerEvents;
392         }
393 
394         /**
395          * @brief Find the first instance of a timer event
396          *
397          * @param[in] eventGroup - Group associated with a timer
398          * @param[in] eventActions - List of actions associated with a timer
399          *
400          * @return - Iterator to the timer event
401          */
402         std::vector<TimerEvent>::iterator findTimer(
403                 const Group& eventGroup,
404                 const std::vector<Action>& eventActions);
405 
406         /**
407          * @brief Add a timer to the list of timer based events
408          *
409          * @param[in] group - Group associated with a timer
410          * @param[in] actions - List of actions associated with a timer
411          * @param[in] tConf - Configuration for the new timer
412          */
413         void addTimer(const Group& group,
414                       const std::vector<Action>& actions,
415                       const TimerConf& tConf);
416 
417         /**
418          * @brief Remove the given timer event
419          *
420          * @param[in] teIter - Iterator pointing to the timer event to remove
421          */
422         inline void removeTimer(std::vector<TimerEvent>::iterator& teIter)
423         {
424             _timerEvents.erase(teIter);
425         }
426 
427         /**
428          * @brief Callback function for event timers that processes the given
429          * actions for a group
430          *
431          * @param[in] eventGroup - Group to process actions on
432          * @param[in] eventActions - List of event actions to run
433          */
434         void timerExpired(const Group& eventGroup,
435                           const std::vector<Action>& eventActions);
436 
437         /**
438          * @brief Get the service for a given path and interface from cached
439          * dataset and add a service that's not found
440          *
441          * @param[in] path - Path to get service for
442          * @param[in] intf - Interface to get service for
443          *
444          * @return - The service name
445          */
446         const std::string& getService(const std::string& path,
447                                       const std::string& intf);
448 
449         /**
450          * @brief Add a set of services for a path and interface
451          * by retrieving all the path subtrees to the given depth
452          * from root for the interface
453          *
454          * @param[in] path - Path to add services for
455          * @param[in] intf - Interface to add services for
456          * @param[in] depth - Depth of tree traversal from root path
457          *
458          * @return - The associated service to the given path and interface
459          * or empty string for no service found
460          */
461         const std::string& addServices(const std::string& path,
462                                        const std::string& intf,
463                                        int32_t depth);
464 
465     private:
466 
467         /**
468          * The dbus object
469          */
470         sdbusplus::bus::bus& _bus;
471 
472         /**
473          * Full speed for the zone
474          */
475         const uint64_t _fullSpeed;
476 
477         /**
478          * The zone number
479          */
480         const size_t _zoneNum;
481 
482         /**
483          * The default floor speed for the zone
484          */
485         const uint64_t _defFloorSpeed;
486 
487         /**
488          * The default ceiling speed for the zone
489          */
490         const uint64_t _defCeilingSpeed;
491 
492         /**
493          * The floor speed to not go below
494          */
495         uint64_t _floorSpeed = _defFloorSpeed;
496 
497         /**
498          * The ceiling speed to not go above
499          */
500         uint64_t _ceilingSpeed = _defCeilingSpeed;
501 
502         /**
503          * The previous sensor value for calculating the ceiling
504          */
505         int64_t _ceilingKeyValue = 0;
506 
507         /**
508          * Automatic fan control active state
509          */
510         bool _isActive = true;
511 
512         /**
513          * Target speed for this zone
514          */
515         uint64_t _targetSpeed = _fullSpeed;
516 
517         /**
518          * Speed increase delta
519          */
520         uint64_t _incSpeedDelta = 0;
521 
522         /**
523          * Speed decrease delta
524          */
525         uint64_t _decSpeedDelta = 0;
526 
527         /**
528          * Requested speed base
529          */
530         uint64_t _requestSpeedBase = 0;
531 
532         /**
533          * Speed increase delay in seconds
534          */
535         std::chrono::seconds _incDelay;
536 
537         /**
538          * Speed decrease interval in seconds
539          */
540         std::chrono::seconds _decInterval;
541 
542         /**
543          * The increase timer object
544          */
545         Timer _incTimer;
546 
547         /**
548          * The decrease timer object
549          */
550         Timer _decTimer;
551 
552         /**
553          * Event loop used on set speed event timers
554          */
555         sdeventplus::Event _eventLoop;
556 
557         /**
558          * The vector of fans in this zone
559          */
560         std::vector<std::unique_ptr<Fan>> _fans;
561 
562         /**
563          * @brief Map of object property values
564          */
565         std::map<std::string,
566                  std::map<std::string,
567                           std::map<std::string,
568                                    PropertyVariantType>>> _properties;
569 
570         /**
571          * @brief Map of active fan control allowed by groups
572          */
573         std::map<const Group, bool> _active;
574 
575         /**
576          * @brief Map of floor change allowed by groups
577          */
578         std::map<const Group, bool> _floorChange;
579 
580         /**
581          * @brief Map of groups controlling decreases allowed
582          */
583         std::map<const Group, bool> _decAllowed;
584 
585         /**
586          * @brief Map of group service names
587          */
588         std::map<const Group, std::vector<Service>> _services;
589 
590         /**
591          * @brief Map tree of paths to services of interfaces
592          */
593         std::map<std::string,
594                 std::map<std::string,
595                 std::vector<std::string>>> _servTree;
596 
597         /**
598          * @brief List of signal event arguments and Dbus matches for callbacks
599          */
600         std::vector<SignalEvent> _signalEvents;
601 
602         /**
603          * @brief List of timers for events
604          */
605         std::vector<TimerEvent> _timerEvents;
606 
607         /**
608          * @brief Get the request speed base if defined, otherwise the
609          * the current target speed is returned
610          *
611          * @return - The request speed base or current target speed
612          */
613         inline auto getRequestSpeedBase() const
614         {
615             return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed;
616         };
617 
618         /**
619          * @brief Dbus signal change callback handler
620          *
621          * @param[in] msg - Expanded sdbusplus message data
622          * @param[in] eventData - The single event's data
623          */
624         void handleEvent(sdbusplus::message::message& msg,
625                          const EventData* eventData);
626 };
627 
628 }
629 }
630 }
631