blob: 6eda2a6b96992395b21c78c98bff6049e4905cc7 [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 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