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