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