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 that wraps a list of actions with a timer
19  * @details Sets up a list of actions to be invoked when the defined timer
20  * expires (or for each expiration of a repeating timer).
21  *
22  * @param[in] tConf - Timer configuration parameters
23  * @param[in] action - List of actions to be called when the timer expires
24  *
25  * @return Action lambda function
26  *     An Action function that creates a timer
27  */
28 Action call_actions_based_on_timer(
29         Timer&& tConf,
30         std::vector<Action>&& actions);
31 
32 /**
33  * @brief An action that sets the floor to the default fan floor speed
34  * @details Sets the fan floor to the defined default fan floor speed when a
35  * service associated to the given group has terminated. Once all services
36  * are functional and providing the sensors again, the fan floor is allowed
37  * to be set normally.
38  *
39  * @param[in] zone - Zone containing fans
40  * @param[in] group - Group of sensors to determine services' states
41  */
42 void default_floor_on_missing_owner(Zone& zone, const Group& group);
43 
44 /**
45  * @brief An action to set a speed when a service owner is missing
46  * @details Sets the fans to the given speed when any service owner associated
47  * to the group is missing. Once all services are functional and providing
48  * the event data again, active fan speed changes are allowed.
49  *
50  * @param[in] speed - Speed to set the zone to
51  *
52  * @return Action lambda function
53  *     An Action function that sets the zone to the given speed if any service
54  *     owners are missing.
55  */
56 Action set_speed_on_missing_owner(uint64_t speed);
57 
58 /**
59  * @brief An action to set the request speed base
60  * @details A new target speed is determined using a speed delta being added
61  * or subtracted, for increases or decrease respectively, from a base speed.
62  * This base speed defaults to be the current target speed or is set to a
63  * different base speed(i.e. the fans' tach feedback speed) to request a new
64  * target from.
65  *
66  * @param[in] zone - Zone containing fans
67  * @param[in] group - Group of sensors to determine base from
68  */
69 void set_request_speed_base_with_max(Zone& zone, const Group& group);
70 
71 /**
72  * @brief An action to set the speed on a zone
73  * @details The zone is held at the given speed when a defined number of
74  * properties in the group are set to the given state
75  *
76  * @param[in] count - Number of properties
77  * @param[in] state - Value the property(s) needed to be set at
78  * @param[in] speed - Speed to set the zone to
79  *
80  * @return Lambda function
81  *     A lambda function to set the zone speed when the number of properties
82  *     within the group are at a certain value
83  */
84 template <typename T>
85 auto count_state_before_speed(size_t count, T&& state, uint64_t speed)
86 {
87     return [count,
88             speed,
89             state = std::forward<T>(state)](auto& zone, auto& group)
90     {
91         size_t numAtState = std::count_if(
92             group.begin(),
93             group.end(),
94             [&zone, &state](auto const& entry)
95             {
96                 try
97                 {
98                     return zone.template getPropertyValue<T>(
99                             entry.first,
100                             std::get<intfPos>(entry.second),
101                             std::get<propPos>(entry.second)) == state;
102                 }
103                 catch (const std::out_of_range& oore)
104                 {
105                     // Default to property not equal when not found
106                     return false;
107                 }
108             });
109         if (numAtState >= count)
110         {
111             zone.setSpeed(speed);
112         }
113         // Update group's fan control active allowed based on action results
114         zone.setActiveAllow(&group, !(numAtState >= count));
115     };
116 }
117 
118 /**
119  * @brief An action to set the floor speed on a zone
120  * @details Based on the average of the defined sensor group values, the floor
121  * speed is selected from the first map key entry that the average sensor value
122  * is less than.
123  *
124  * @param[in] val_to_speed - Ordered map of sensor value-to-speed
125  *
126  * @return Action lambda function
127  *     An Action function to set the zone's floor speed when the average of
128  *     property values within the group is below the lowest sensor value given
129  */
130 Action set_floor_from_average_sensor_value(
131         std::map<int64_t, uint64_t>&& val_to_speed);
132 
133 /**
134  * @brief An action to set the ceiling speed on a zone
135  * @details Based on the average of the defined sensor group values, the
136  * ceiling speed is selected from the map key transition point that the average
137  * sensor value falls within depending on the key values direction from what
138  * was previously read.
139  *
140  * @param[in] val_to_speed - Ordered map of sensor value-to-speed transitions
141  *
142  * @return Action lambda function
143  *     An Action function to set the zone's ceiling speed when the average of
144  *     property values within the group is above(increasing) or
145  *     below(decreasing) the key transition point
146  */
147 Action set_ceiling_from_average_sensor_value(
148         std::map<int64_t, uint64_t>&& val_to_speed);
149 
150 /**
151  * @brief An action to set the speed increase delta and request speed change
152  * @details Provides the ability to determine what the net increase delta the
153  * zone's fan speeds should be updated by from their current target speed and
154  * request that new target speed.
155  *
156  * @param[in] state - State to compare the group's property value to
157  * @param[in] factor - Factor to apply to the calculated net delta
158  * @param[in] speedDelta - Speed delta of the group
159  *
160  * @return Lambda function
161  *     A lambda function that determines the net increase delta and requests
162  * a new target speed with that increase for the zone.
163  */
164 template <typename T>
165 auto set_net_increase_speed(T&& state, T&& factor, uint64_t speedDelta)
166 {
167     return [speedDelta,
168             factor = std::forward<T>(factor),
169             state = std::forward<T>(state)](auto& zone, auto& group)
170     {
171         auto netDelta = zone.getIncSpeedDelta();
172         std::for_each(
173             group.begin(),
174             group.end(),
175             [&zone, &state, &factor, &speedDelta, &netDelta](
176                 auto const& entry)
177             {
178                 try
179                 {
180                     T value = zone.template getPropertyValue<T>(
181                             entry.first,
182                             std::get<intfPos>(entry.second),
183                             std::get<propPos>(entry.second));
184                     // TODO openbmc/phosphor-fan-presence#7 - Support possible
185                     // state types for comparison
186                     if (value >= state)
187                     {
188                         // Increase by at least a single delta(factor)
189                         // to attempt bringing under 'state'
190                         auto delta = std::max(
191                             (value - state),
192                             factor);
193                         // Increase is the factor applied to the
194                         // difference times the given speed delta
195                         netDelta = std::max(
196                             netDelta,
197                             (delta/factor) * speedDelta);
198                     }
199                 }
200                 catch (const std::out_of_range& oore)
201                 {
202                     // Property value not found, netDelta unchanged
203                 }
204             }
205         );
206         // Request speed change for target speed update
207         zone.requestSpeedIncrease(netDelta);
208     };
209 }
210 
211 /**
212  * @brief An action to set the speed decrease delta and request speed change
213  * @details Provides the ability to determine what the net decrease delta each
214  * zone's fan speeds should be updated by from their current target speed, and
215  * request that speed change occur on the next decrease interval.
216  *
217  * @param[in] state - State to compare the group's property value to
218  * @param[in] factor - Factor to apply to the calculated net delta
219  * @param[in] speedDelta - Speed delta of the group
220  *
221  * @return Lambda function
222  *     A lambda function that determines the net decrease delta and requests
223  * a new target speed with that decrease for the zone.
224  */
225 template <typename T>
226 auto set_net_decrease_speed(T&& state, T&& factor, uint64_t speedDelta)
227 {
228     return [speedDelta,
229             factor = std::forward<T>(factor),
230             state = std::forward<T>(state)](auto& zone, auto& group)
231     {
232         auto netDelta = zone.getDecSpeedDelta();
233         for (auto& entry : group)
234         {
235             try
236             {
237                 T value = zone.template getPropertyValue<T>(
238                         entry.first,
239                         std::get<intfPos>(entry.second),
240                         std::get<propPos>(entry.second));
241                 // TODO openbmc/phosphor-fan-presence#7 - Support possible
242                 // state types for comparison
243                 if (value < state)
244                 {
245                     if (netDelta == 0)
246                     {
247                         netDelta = ((state - value)/factor) * speedDelta;
248                     }
249                     else
250                     {
251                         // Decrease is the factor applied to the
252                         // difference times the given speed delta
253                         netDelta = std::min(
254                             netDelta,
255                             ((state - value)/factor) * speedDelta);
256                     }
257                 }
258                 else
259                 {
260                     // No decrease allowed for this group
261                     netDelta = 0;
262                     break;
263                 }
264             }
265             catch (const std::out_of_range& oore)
266             {
267                 // Property value not found, netDelta unchanged
268             }
269         }
270         // Update group's decrease allowed state
271         zone.setDecreaseAllow(&group, !(netDelta == 0));
272         // Request speed decrease to occur on decrease interval
273         zone.requestSpeedDecrease(netDelta);
274     };
275 }
276 
277 } // namespace action
278 } // namespace control
279 } // namespace fan
280 } // namespace phosphor
281