blob: 325cbbdc748744087b608c8b2cc49fe877b3ace9 [file] [log] [blame]
Matthew Barth17d1fe22017-05-11 15:00:36 -05001#pragma once
2
3#include <algorithm>
Matthew Barth4af419c2017-06-12 13:39:31 -05004#include <numeric>
Matthew Barth17d1fe22017-05-11 15:00:36 -05005
6namespace phosphor
7{
8namespace fan
9{
10namespace control
11{
12namespace action
13{
14
15/**
16 * @brief An action to set the speed on a zone
Matthew Barth861d77c2017-05-22 14:18:25 -050017 * @details The zone is held at the given speed when a defined number of
Matthew Barth17d1fe22017-05-11 15:00:36 -050018 * properties in the group are set to the given state
19 *
20 * @param[in] count - Number of properties
21 * @param[in] state - Value the property(s) needed to be set at
22 * @param[in] speed - Speed to set the zone to
23 *
24 * @return Lambda function
25 * A lambda function to set the zone speed when the number of properties
26 * within the group are at a certain value
27 */
Matthew Barth9e741ed2017-06-02 16:29:09 -050028template <typename T>
29auto count_state_before_speed(size_t count, T&& state, uint64_t speed)
Matthew Barth17d1fe22017-05-11 15:00:36 -050030{
Matthew Barth9e741ed2017-06-02 16:29:09 -050031 return [count,
32 speed,
33 state = std::forward<T>(state)](auto& zone, auto& group)
Matthew Barth17d1fe22017-05-11 15:00:36 -050034 {
35 size_t numAtState = std::count_if(
36 group.begin(),
37 group.end(),
38 [&zone, &state](auto const& entry)
39 {
Matthew Barth9e741ed2017-06-02 16:29:09 -050040 return zone.template getPropertyValue<T>(
Matthew Barth17d1fe22017-05-11 15:00:36 -050041 entry.first,
Matthew Barthcec5ab72017-06-02 15:20:56 -050042 std::get<intfPos>(entry.second),
Matthew Barth17d1fe22017-05-11 15:00:36 -050043 std::get<propPos>(entry.second)) == state;
44 });
Matthew Barth861d77c2017-05-22 14:18:25 -050045 // Update group's fan control active allowed based on action results
46 zone.setActiveAllow(&group, !(numAtState >= count));
Matthew Barth17d1fe22017-05-11 15:00:36 -050047 if (numAtState >= count)
48 {
49 zone.setSpeed(speed);
50 }
51 };
52}
53
Matthew Barth4af419c2017-06-12 13:39:31 -050054/**
55 * @brief An action to set the floor speed on a zone
56 * @details Based on the average of the defined sensor group values, the floor
57 * speed is selected from the first map key entry that the average sensor value
58 * is less than.
59 *
60 * @param[in] val_to_speed - Ordered map of sensor value-to-speed
61 *
62 * @return Lambda function
63 * A lambda function to set the zone's floor speed when the average of
64 * property values within the group is below the lowest sensor value given
65 */
66auto set_floor_from_average_sensor_value(
67 std::map<int64_t, uint64_t>&& val_to_speed)
68{
69 return [val_to_speed = std::move(val_to_speed)](auto& zone, auto& group)
70 {
71 auto speed = zone.getDefFloor();
72 if (group.size() != 0)
73 {
74 auto sumValue = std::accumulate(
75 group.begin(),
76 group.end(),
77 0,
78 [&zone](int64_t sum, auto const& entry)
79 {
80 return sum + zone.template getPropertyValue<int64_t>(
81 entry.first,
82 std::get<intfPos>(entry.second),
83 std::get<propPos>(entry.second));
84 });
85 auto avgValue= sumValue / group.size();
86 auto it = std::find_if(
87 val_to_speed.begin(),
88 val_to_speed.end(),
89 [&avgValue](auto const& entry)
90 {
91 return avgValue < entry.first;
92 }
93 );
94 if (it != std::end(val_to_speed))
95 {
96 speed = (*it).second;
97 }
98 }
99 zone.setFloor(speed);
100 };
101}
102
Matthew Barthe0ca13e2017-06-13 16:29:09 -0500103/**
104 * @brief An action to set the ceiling speed on a zone
105 * @details Based on the average of the defined sensor group values, the ceiling
106 * speed is selected from the map key transition point that the average sensor
107 * value falls within depending on the key values direction from what was
108 * previously read.
109 *
110 * @param[in] val_to_speed - Ordered map of sensor value-to-speed transitions
111 *
112 * @return Lambda function
113 * A lambda function to set the zone's ceiling speed when the average of
114 * property values within the group is above(increasing) or
115 * below(decreasing) the key transition point
116 */
117auto set_ceiling_from_average_sensor_value(
118 std::map<int64_t, uint64_t>&& val_to_speed)
119{
120 return [val_to_speed = std::move(val_to_speed)](auto& zone, auto& group)
121 {
122 auto speed = zone.getCeiling();
123 if (group.size() != 0)
124 {
125 auto sumValue = std::accumulate(
126 group.begin(),
127 group.end(),
128 0,
129 [&zone](int64_t sum, auto const& entry)
130 {
131 return sum + zone.template getPropertyValue<int64_t>(
132 entry.first,
133 std::get<intfPos>(entry.second),
134 std::get<propPos>(entry.second));
135 });
136 auto avgValue = sumValue / group.size();
137 auto prevValue = zone.swapCeilingKeyValue(avgValue);
138 if (avgValue != prevValue)
139 {// Only check if previous and new values differ
140 if (avgValue < prevValue)
141 {// Value is decreasing from previous
142 for (auto it = val_to_speed.rbegin();
143 it != val_to_speed.rend();
144 ++it)
145 {
146 if (it == val_to_speed.rbegin() &&
147 avgValue >= it->first)
148 {
149 // Value is at/above last map key,
150 // set ceiling speed to the last map key's value
151 speed = it->second;
152 break;
153 }
154 else if (std::next(it, 1) == val_to_speed.rend() &&
155 avgValue <= it->first)
156 {
157 // Value is at/below first map key,
158 // set ceiling speed to the first map key's value
159 speed = it->second;
160 break;
161 }
162 if (avgValue < it->first &&
163 it->first <= prevValue)
164 {
165 // Value decreased & transitioned across a map key,
166 // update ceiling speed to this map key's value
167 // when new value is below map's key and the key
168 // is at/below the previous value
169 speed = it->second;
170 }
171 }
172 }
173 else
174 {// Value is increasing from previous
175 for (auto it = val_to_speed.begin();
176 it != val_to_speed.end();
177 ++it)
178 {
179 if (it == val_to_speed.begin() &&
180 avgValue <= it->first)
181 {
182 // Value is at/below first map key,
183 // set ceiling speed to the first map key's value
184 speed = it->second;
185 break;
186 }
187 else if (std::next(it, 1) == val_to_speed.end() &&
188 avgValue >= it->first)
189 {
190 // Value is at/above last map key,
191 // set ceiling speed to the last map key's value
192 speed = it->second;
193 break;
194 }
195 if (avgValue > it->first &&
196 it->first >= prevValue)
197 {
198 // Value increased & transitioned across a map key,
199 // update ceiling speed to this map key's value
200 // when new value is above map's key and the key
201 // is at/above the previous value
202 speed = it->second;
203 }
204 }
205 }
206 }
207 }
208 zone.setCeiling(speed);
209 };
210}
211
Matthew Barth24623522017-06-21 14:09:57 -0500212/**
213 * @brief An action to set the speed increase delta and request speed change
214 * @details Provides the ability to determine what the net increase delta the
215 * zone's fan speeds should be updated by from their current target speed and
216 * request that new target speed.
217 *
218 * @param[in] state - State to compare the group's property value to
219 * @param[in] speedDelta - Speed delta of the group
220 *
221 * @return Lambda function
222 * A lambda function that determines the net increase delta and requests
223 * a new target speed with that increase for the zone.
224 */
225template <typename T>
226auto set_net_increase_speed(T&& state, uint64_t speedDelta)
227{
228 return [speedDelta,
229 state = std::forward<T>(state)](auto& zone, auto& group)
230 {
231 auto netDelta = zone.getIncSpeedDelta();
232 std::for_each(
233 group.begin(),
234 group.end(),
235 [&zone, &state, &speedDelta, &netDelta](auto const& entry)
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 // Increase by at least a single delta
246 // to attempt bringing under 'state'
247 auto delta = std::max((value - state), 1);
248 // Increase is the difference times the given speed delta
249 netDelta = std::max(netDelta, delta * speedDelta);
250 }
251 }
252 );
Matthew Barth240397b2017-06-22 11:23:30 -0500253 // Request speed change for target speed update
254 zone.requestSpeedIncrease(netDelta);
Matthew Barth24623522017-06-21 14:09:57 -0500255 };
256}
257
Matthew Barth0ce99d82017-06-22 15:07:29 -0500258/**
259 * @brief An action to set the speed decrease delta and request speed change
260 * @details Provides the ability to determine what the net decrease delta each
261 * zone's fan speeds should be updated by from their current target speed, and
262 * request that speed change occur on the next decrease interval.
263 *
264 * @param[in] state - State to compare the group's property value to
265 * @param[in] speedDelta - Speed delta of the group
266 *
267 * @return Lambda function
268 * A lambda function that determines the net decrease delta and requests
269 * a new target speed with that decrease for the zone.
270 */
271template <typename T>
272auto set_net_decrease_speed(T&& state, uint64_t speedDelta)
273{
274 return [speedDelta,
275 state = std::forward<T>(state)](auto& zone, auto& group)
276 {
277 auto netDelta = zone.getDecSpeedDelta();
278 std::for_each(
279 group.begin(),
280 group.end(),
281 [&zone, &state, &speedDelta, &netDelta](auto const& entry)
282 {
283 T value = zone.template getPropertyValue<T>(
284 entry.first,
285 std::get<intfPos>(entry.second),
286 std::get<propPos>(entry.second));
287 // TODO openbmc/phosphor-fan-presence#7 - Support possible
288 // state types for comparison
289 if (value < state)
290 {
291 if (netDelta == 0)
292 {
293 netDelta = (state - value) * speedDelta;
294 }
295 else
296 {
297 // Decrease is the difference times
298 // the given speed delta
299 netDelta = std::min(netDelta,
300 (state - value) * speedDelta);
301 }
302 }
303 }
304 );
305 // Request speed decrease to occur on decrease interval
306 zone.requestSpeedDecrease(netDelta);
307 };
308}
309
Matthew Barth17d1fe22017-05-11 15:00:36 -0500310} // namespace action
311} // namespace control
312} // namespace fan
313} // namespace phosphor