blob: 8ecd30cce70519902421d0af9f15553f71390ddf [file] [log] [blame]
Matthew Barthb280bfa2017-09-15 09:56:50 -05001#include "actions.hpp"
2
3namespace phosphor
4{
5namespace fan
6{
7namespace control
8{
9namespace action
10{
11
12using namespace phosphor::fan;
13
Matthew Barth2a646c52017-10-05 17:04:11 -050014Action call_actions_based_on_timer(Timer&& tConf, std::vector<Action>&& actions)
15{
16 return [tConf = std::move(tConf),
17 actions = std::move(actions)](control::Zone& zone,
18 const Group& group)
19 {
20 try
21 {
22 // Find any services that do not have an owner
23 auto services = zone.getGroupServices(&group);
24 auto setTimer = std::any_of(
25 services.begin(),
26 services.end(),
27 [](const auto& s)
28 {
29 return !std::get<hasOwnerPos>(s);
30 });
31 if (setTimer &&
32 zone.findTimer(group, actions) ==
33 std::end(zone.getTimerEvents()))
34 {
35 // Associate event data with timer
36 std::unique_ptr<EventData> eventData =
37 std::make_unique<EventData>(
38 EventData
39 {
40 group,
41 "",
42 nullptr,
43 actions
44 }
45 );
46 // Create/start timer and associate event data with it
47 std::unique_ptr<util::Timer> timer =
48 std::make_unique<util::Timer>(
49 zone.getEventPtr(),
50 [&zone,
51 actions = &actions,
52 group = &group]()
53 {
54 zone.timerExpired(*group, *actions);
55 });
56 if (!timer->running())
57 {
58 timer->start(std::get<intervalPos>(tConf),
59 std::get<typePos>(tConf));
60 }
61 zone.addTimer(std::move(eventData), std::move(timer));
62 }
63 else
64 {
65 // Stop and remove any timers for this group
66 auto timer = zone.findTimer(group, actions);
67 if (timer != std::end(zone.getTimerEvents()))
68 {
69 if (std::get<timerTimerPos>(*timer)->running())
70 {
71 std::get<timerTimerPos>(*timer)->stop();
72 }
73 zone.removeTimer(timer);
74 }
75 }
76 }
77 catch (const std::out_of_range& oore)
78 {
79 // Group not found, no timers set
80 }
81 };
82}
83
Matthew Barth98726c42017-10-17 10:35:20 -050084void default_floor_on_missing_owner(Zone& zone, const Group& group)
85{
Matthew Barth480787c2017-11-06 11:00:00 -060086 // Set/update the services of the group
87 zone.setServices(&group);
Matthew Barth98726c42017-10-17 10:35:20 -050088 auto services = zone.getGroupServices(&group);
89 auto defFloor = std::any_of(
90 services.begin(),
91 services.end(),
92 [](const auto& s)
93 {
94 return !std::get<hasOwnerPos>(s);
95 });
96 if (defFloor)
97 {
98 zone.setFloor(zone.getDefFloor());
99 }
100 // Update fan control floor change allowed
101 zone.setFloorChangeAllow(&group, !defFloor);
102}
103
Matthew Barth0decd1b2017-10-24 15:58:17 -0500104Action set_speed_on_missing_owner(uint64_t speed)
105{
106 return [speed](control::Zone& zone, const Group& group)
107 {
Matthew Barth480787c2017-11-06 11:00:00 -0600108 // Set/update the services of the group
109 zone.setServices(&group);
Matthew Barth0decd1b2017-10-24 15:58:17 -0500110 auto services = zone.getGroupServices(&group);
111 auto missingOwner = std::any_of(
112 services.begin(),
113 services.end(),
114 [](const auto& s)
115 {
116 return !std::get<hasOwnerPos>(s);
117 });
118 if (missingOwner)
119 {
120 zone.setSpeed(speed);
121 }
122 // Update group's fan control active allowed based on action results
123 zone.setActiveAllow(&group, !missingOwner);
124 };
125}
126
Matthew Barthb280bfa2017-09-15 09:56:50 -0500127void set_request_speed_base_with_max(control::Zone& zone,
128 const Group& group)
129{
130 int64_t base = 0;
131 std::for_each(
132 group.begin(),
133 group.end(),
134 [&zone, &base](auto const& entry)
135 {
136 try
137 {
138 auto value = zone.template getPropertyValue<int64_t>(
139 entry.first,
140 std::get<intfPos>(entry.second),
141 std::get<propPos>(entry.second));
142 base = std::max(base, value);
143 }
144 catch (const std::out_of_range& oore)
145 {
146 // Property value not found, base request speed unchanged
147 }
148 });
149 // A request speed base of 0 defaults to the current target speed
150 zone.setRequestSpeedBase(base);
151}
152
153Action set_floor_from_average_sensor_value(
154 std::map<int64_t, uint64_t>&& val_to_speed)
155{
156 return [val_to_speed = std::move(val_to_speed)](control::Zone& zone,
157 const Group& group)
158 {
159 auto speed = zone.getDefFloor();
160 if (group.size() != 0)
161 {
162 auto count = 0;
163 auto sumValue = std::accumulate(
164 group.begin(),
165 group.end(),
166 0,
167 [&zone, &count](int64_t sum, auto const& entry)
168 {
169 try
170 {
171 return sum +
172 zone.template getPropertyValue<int64_t>(
173 entry.first,
174 std::get<intfPos>(entry.second),
175 std::get<propPos>(entry.second));
176 }
177 catch (const std::out_of_range& oore)
178 {
179 count++;
180 return sum;
181 }
182 });
183 if ((group.size() - count) > 0)
184 {
185 auto groupSize = static_cast<int64_t>(group.size());
186 auto avgValue = sumValue / (groupSize - count);
187 auto it = std::find_if(
188 val_to_speed.begin(),
189 val_to_speed.end(),
190 [&avgValue](auto const& entry)
191 {
192 return avgValue < entry.first;
193 }
194 );
195 if (it != std::end(val_to_speed))
196 {
197 speed = (*it).second;
198 }
199 }
200 }
201 zone.setFloor(speed);
202 };
203}
204
205Action set_ceiling_from_average_sensor_value(
206 std::map<int64_t, uint64_t>&& val_to_speed)
207{
208 return [val_to_speed = std::move(val_to_speed)](Zone& zone,
209 const Group& group)
210 {
211 auto speed = zone.getCeiling();
212 if (group.size() != 0)
213 {
214 auto count = 0;
215 auto sumValue = std::accumulate(
216 group.begin(),
217 group.end(),
218 0,
219 [&zone, &count](int64_t sum, auto const& entry)
220 {
221 try
222 {
223 return sum +
224 zone.template getPropertyValue<int64_t>(
225 entry.first,
226 std::get<intfPos>(entry.second),
227 std::get<propPos>(entry.second));
228 }
229 catch (const std::out_of_range& oore)
230 {
231 count++;
232 return sum;
233 }
234 });
235 if ((group.size() - count) > 0)
236 {
237 auto groupSize = static_cast<int64_t>(group.size());
238 auto avgValue = sumValue / (groupSize - count);
239 auto prevValue = zone.swapCeilingKeyValue(avgValue);
240 if (avgValue != prevValue)
241 {// Only check if previous and new values differ
242 if (avgValue < prevValue)
243 {// Value is decreasing from previous
244 for (auto it = val_to_speed.rbegin();
245 it != val_to_speed.rend();
246 ++it)
247 {
248 if (it == val_to_speed.rbegin() &&
249 avgValue >= it->first)
250 {
251 // Value is at/above last map key, set
252 // ceiling speed to the last map key's value
253 speed = it->second;
254 break;
255 }
256 else if (std::next(it, 1) == val_to_speed.rend() &&
257 avgValue <= it->first)
258 {
259 // Value is at/below first map key, set
260 // ceiling speed to the first map key's value
261 speed = it->second;
262 break;
263 }
264 if (avgValue < it->first &&
265 it->first <= prevValue)
266 {
267 // Value decreased & transitioned across
268 // a map key, update ceiling speed to this
269 // map key's value when new value is below
270 // map's key and the key is at/below the
271 // previous value
272 speed = it->second;
273 }
274 }
275 }
276 else
277 {// Value is increasing from previous
278 for (auto it = val_to_speed.begin();
279 it != val_to_speed.end();
280 ++it)
281 {
282 if (it == val_to_speed.begin() &&
283 avgValue <= it->first)
284 {
285 // Value is at/below first map key, set
286 // ceiling speed to the first map key's value
287 speed = it->second;
288 break;
289 }
290 else if (std::next(it, 1) == val_to_speed.end() &&
291 avgValue >= it->first)
292 {
293 // Value is at/above last map key, set
294 // ceiling speed to the last map key's value
295 speed = it->second;
296 break;
297 }
298 if (avgValue > it->first &&
299 it->first >= prevValue)
300 {
301 // Value increased & transitioned across
302 // a map key, update ceiling speed to this
303 // map key's value when new value is above
304 // map's key and the key is at/above the
305 // previous value
306 speed = it->second;
307 }
308 }
309 }
310 }
311 }
312 }
313 zone.setCeiling(speed);
314 };
315}
316
317} // namespace action
318} // namespace control
319} // namespace fan
320} // namespace phosphor