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