1 #pragma once
2 
3 #include <algorithm>
4 #include <numeric>
5 #include "types.hpp"
6 #include "zone.hpp"
7 
8 namespace phosphor
9 {
10 namespace fan
11 {
12 namespace control
13 {
14 namespace action
15 {
16 
17 /**
18  * @brief An action to set the request speed base
19  * @details A new target speed is determined using a speed delta being added
20  * or subtracted, for increases or decrease respectively, from a base speed.
21  * This base speed defaults to be the current target speed or is set to a
22  * different base speed(i.e. the fans' tach feedback speed) to request a new
23  * target from.
24  *
25  * @param[in] zone - Zone containing fans
26  * @param[in] group - Group of sensors to determine base from
27  */
28 void set_request_speed_base_with_max(Zone& zone, const Group& group);
29 
30 /**
31  * @brief An action to set the speed on a zone
32  * @details The zone is held at the given speed when a defined number of
33  * properties in the group are set to the given state
34  *
35  * @param[in] count - Number of properties
36  * @param[in] state - Value the property(s) needed to be set at
37  * @param[in] speed - Speed to set the zone to
38  *
39  * @return Lambda function
40  *     A lambda function to set the zone speed when the number of properties
41  *     within the group are at a certain value
42  */
43 template <typename T>
44 auto count_state_before_speed(size_t count, T&& state, uint64_t speed)
45 {
46     return [count,
47             speed,
48             state = std::forward<T>(state)](auto& zone, auto& group)
49     {
50         size_t numAtState = std::count_if(
51             group.begin(),
52             group.end(),
53             [&zone, &state](auto const& entry)
54             {
55                 try
56                 {
57                     return zone.template getPropertyValue<T>(
58                             entry.first,
59                             std::get<intfPos>(entry.second),
60                             std::get<propPos>(entry.second)) == state;
61                 }
62                 catch (const std::out_of_range& oore)
63                 {
64                     // Default to property not equal when not found
65                     return false;
66                 }
67             });
68         if (numAtState >= count)
69         {
70             zone.setSpeed(speed);
71         }
72         // Update group's fan control active allowed based on action results
73         zone.setActiveAllow(&group, !(numAtState >= count));
74     };
75 }
76 
77 /**
78  * @brief An action to set the floor speed on a zone
79  * @details Based on the average of the defined sensor group values, the floor
80  * speed is selected from the first map key entry that the average sensor value
81  * is less than.
82  *
83  * @param[in] val_to_speed - Ordered map of sensor value-to-speed
84  *
85  * @return Action lambda function
86  *     An Action function to set the zone's floor speed when the average of
87  *     property values within the group is below the lowest sensor value given
88  */
89 Action set_floor_from_average_sensor_value(
90         std::map<int64_t, uint64_t>&& val_to_speed);
91 
92 /**
93  * @brief An action to set the ceiling speed on a zone
94  * @details Based on the average of the defined sensor group values, the
95  * ceiling speed is selected from the map key transition point that the average
96  * sensor value falls within depending on the key values direction from what
97  * was previously read.
98  *
99  * @param[in] val_to_speed - Ordered map of sensor value-to-speed transitions
100  *
101  * @return Action lambda function
102  *     An Action function to set the zone's ceiling speed when the average of
103  *     property values within the group is above(increasing) or
104  *     below(decreasing) the key transition point
105  */
106 Action set_ceiling_from_average_sensor_value(
107         std::map<int64_t, uint64_t>&& val_to_speed);
108 
109 /**
110  * @brief An action to set the speed increase delta and request speed change
111  * @details Provides the ability to determine what the net increase delta the
112  * zone's fan speeds should be updated by from their current target speed and
113  * request that new target speed.
114  *
115  * @param[in] state - State to compare the group's property value to
116  * @param[in] factor - Factor to apply to the calculated net delta
117  * @param[in] speedDelta - Speed delta of the group
118  *
119  * @return Lambda function
120  *     A lambda function that determines the net increase delta and requests
121  * a new target speed with that increase for the zone.
122  */
123 template <typename T>
124 auto set_net_increase_speed(T&& state, T&& factor, uint64_t speedDelta)
125 {
126     return [speedDelta,
127             factor = std::forward<T>(factor),
128             state = std::forward<T>(state)](auto& zone, auto& group)
129     {
130         auto netDelta = zone.getIncSpeedDelta();
131         std::for_each(
132             group.begin(),
133             group.end(),
134             [&zone, &state, &factor, &speedDelta, &netDelta](
135                 auto const& entry)
136             {
137                 try
138                 {
139                     T value = zone.template getPropertyValue<T>(
140                             entry.first,
141                             std::get<intfPos>(entry.second),
142                             std::get<propPos>(entry.second));
143                     // TODO openbmc/phosphor-fan-presence#7 - Support possible
144                     // state types for comparison
145                     if (value >= state)
146                     {
147                         // Increase by at least a single delta(factor)
148                         // to attempt bringing under 'state'
149                         auto delta = std::max(
150                             (value - state),
151                             factor);
152                         // Increase is the factor applied to the
153                         // difference times the given speed delta
154                         netDelta = std::max(
155                             netDelta,
156                             (delta/factor) * speedDelta);
157                     }
158                 }
159                 catch (const std::out_of_range& oore)
160                 {
161                     // Property value not found, netDelta unchanged
162                 }
163             }
164         );
165         // Request speed change for target speed update
166         zone.requestSpeedIncrease(netDelta);
167     };
168 }
169 
170 /**
171  * @brief An action to set the speed decrease delta and request speed change
172  * @details Provides the ability to determine what the net decrease delta each
173  * zone's fan speeds should be updated by from their current target speed, and
174  * request that speed change occur on the next decrease interval.
175  *
176  * @param[in] state - State to compare the group's property value to
177  * @param[in] factor - Factor to apply to the calculated net delta
178  * @param[in] speedDelta - Speed delta of the group
179  *
180  * @return Lambda function
181  *     A lambda function that determines the net decrease delta and requests
182  * a new target speed with that decrease for the zone.
183  */
184 template <typename T>
185 auto set_net_decrease_speed(T&& state, T&& factor, uint64_t speedDelta)
186 {
187     return [speedDelta,
188             factor = std::forward<T>(factor),
189             state = std::forward<T>(state)](auto& zone, auto& group)
190     {
191         auto netDelta = zone.getDecSpeedDelta();
192         std::for_each(
193             group.begin(),
194             group.end(),
195             [&zone, &state, &factor, &speedDelta, &netDelta](auto const& entry)
196             {
197                 try
198                 {
199                     T value = zone.template getPropertyValue<T>(
200                             entry.first,
201                             std::get<intfPos>(entry.second),
202                             std::get<propPos>(entry.second));
203                     // TODO openbmc/phosphor-fan-presence#7 - Support possible
204                     // state types for comparison
205                     if (value < state)
206                     {
207                         if (netDelta == 0)
208                         {
209                             netDelta = ((state - value)/factor) * speedDelta;
210                         }
211                         else
212                         {
213                             // Decrease is the factor applied to the
214                             // difference times the given speed delta
215                             netDelta = std::min(
216                                 netDelta,
217                                 ((state - value)/factor) * speedDelta);
218                         }
219                     }
220                 }
221                 catch (const std::out_of_range& oore)
222                 {
223                     // Property value not found, netDelta unchanged
224                 }
225             }
226         );
227         // Request speed decrease to occur on decrease interval
228         zone.requestSpeedDecrease(netDelta);
229     };
230 }
231 
232 } // namespace action
233 } // namespace control
234 } // namespace fan
235 } // namespace phosphor
236