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