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