blob: 66bba2bee0842020579a7954d723f345559654c1 [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{
86 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 {
106 auto services = zone.getGroupServices(&group);
107 auto missingOwner = std::any_of(
108 services.begin(),
109 services.end(),
110 [](const auto& s)
111 {
112 return !std::get<hasOwnerPos>(s);
113 });
114 if (missingOwner)
115 {
116 zone.setSpeed(speed);
117 }
118 // Update group's fan control active allowed based on action results
119 zone.setActiveAllow(&group, !missingOwner);
120 };
121}
122
Matthew Barthb280bfa2017-09-15 09:56:50 -0500123void set_request_speed_base_with_max(control::Zone& zone,
124 const Group& group)
125{
126 int64_t base = 0;
127 std::for_each(
128 group.begin(),
129 group.end(),
130 [&zone, &base](auto const& entry)
131 {
132 try
133 {
134 auto value = zone.template getPropertyValue<int64_t>(
135 entry.first,
136 std::get<intfPos>(entry.second),
137 std::get<propPos>(entry.second));
138 base = std::max(base, value);
139 }
140 catch (const std::out_of_range& oore)
141 {
142 // Property value not found, base request speed unchanged
143 }
144 });
145 // A request speed base of 0 defaults to the current target speed
146 zone.setRequestSpeedBase(base);
147}
148
149Action set_floor_from_average_sensor_value(
150 std::map<int64_t, uint64_t>&& val_to_speed)
151{
152 return [val_to_speed = std::move(val_to_speed)](control::Zone& zone,
153 const Group& group)
154 {
155 auto speed = zone.getDefFloor();
156 if (group.size() != 0)
157 {
158 auto count = 0;
159 auto sumValue = std::accumulate(
160 group.begin(),
161 group.end(),
162 0,
163 [&zone, &count](int64_t sum, auto const& entry)
164 {
165 try
166 {
167 return sum +
168 zone.template getPropertyValue<int64_t>(
169 entry.first,
170 std::get<intfPos>(entry.second),
171 std::get<propPos>(entry.second));
172 }
173 catch (const std::out_of_range& oore)
174 {
175 count++;
176 return sum;
177 }
178 });
179 if ((group.size() - count) > 0)
180 {
181 auto groupSize = static_cast<int64_t>(group.size());
182 auto avgValue = sumValue / (groupSize - count);
183 auto it = std::find_if(
184 val_to_speed.begin(),
185 val_to_speed.end(),
186 [&avgValue](auto const& entry)
187 {
188 return avgValue < entry.first;
189 }
190 );
191 if (it != std::end(val_to_speed))
192 {
193 speed = (*it).second;
194 }
195 }
196 }
197 zone.setFloor(speed);
198 };
199}
200
201Action set_ceiling_from_average_sensor_value(
202 std::map<int64_t, uint64_t>&& val_to_speed)
203{
204 return [val_to_speed = std::move(val_to_speed)](Zone& zone,
205 const Group& group)
206 {
207 auto speed = zone.getCeiling();
208 if (group.size() != 0)
209 {
210 auto count = 0;
211 auto sumValue = std::accumulate(
212 group.begin(),
213 group.end(),
214 0,
215 [&zone, &count](int64_t sum, auto const& entry)
216 {
217 try
218 {
219 return sum +
220 zone.template getPropertyValue<int64_t>(
221 entry.first,
222 std::get<intfPos>(entry.second),
223 std::get<propPos>(entry.second));
224 }
225 catch (const std::out_of_range& oore)
226 {
227 count++;
228 return sum;
229 }
230 });
231 if ((group.size() - count) > 0)
232 {
233 auto groupSize = static_cast<int64_t>(group.size());
234 auto avgValue = sumValue / (groupSize - count);
235 auto prevValue = zone.swapCeilingKeyValue(avgValue);
236 if (avgValue != prevValue)
237 {// Only check if previous and new values differ
238 if (avgValue < prevValue)
239 {// Value is decreasing from previous
240 for (auto it = val_to_speed.rbegin();
241 it != val_to_speed.rend();
242 ++it)
243 {
244 if (it == val_to_speed.rbegin() &&
245 avgValue >= it->first)
246 {
247 // Value is at/above last map key, set
248 // ceiling speed to the last map key's value
249 speed = it->second;
250 break;
251 }
252 else if (std::next(it, 1) == val_to_speed.rend() &&
253 avgValue <= it->first)
254 {
255 // Value is at/below first map key, set
256 // ceiling speed to the first map key's value
257 speed = it->second;
258 break;
259 }
260 if (avgValue < it->first &&
261 it->first <= prevValue)
262 {
263 // Value decreased & transitioned across
264 // a map key, update ceiling speed to this
265 // map key's value when new value is below
266 // map's key and the key is at/below the
267 // previous value
268 speed = it->second;
269 }
270 }
271 }
272 else
273 {// Value is increasing from previous
274 for (auto it = val_to_speed.begin();
275 it != val_to_speed.end();
276 ++it)
277 {
278 if (it == val_to_speed.begin() &&
279 avgValue <= it->first)
280 {
281 // Value is at/below first map key, set
282 // ceiling speed to the first map key's value
283 speed = it->second;
284 break;
285 }
286 else if (std::next(it, 1) == val_to_speed.end() &&
287 avgValue >= it->first)
288 {
289 // Value is at/above last map key, set
290 // ceiling speed to the last map key's value
291 speed = it->second;
292 break;
293 }
294 if (avgValue > it->first &&
295 it->first >= prevValue)
296 {
297 // Value increased & transitioned across
298 // a map key, update ceiling speed to this
299 // map key's value when new value is above
300 // map's key and the key is at/above the
301 // previous value
302 speed = it->second;
303 }
304 }
305 }
306 }
307 }
308 }
309 zone.setCeiling(speed);
310 };
311}
312
313} // namespace action
314} // namespace control
315} // namespace fan
316} // namespace phosphor