blob: b1eb9bea72b925d61c1907f5d0ee750fd04abbde [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 Barthb280bfa2017-09-15 09:56:50 -050084void set_request_speed_base_with_max(control::Zone& zone,
85 const Group& group)
86{
87 int64_t base = 0;
88 std::for_each(
89 group.begin(),
90 group.end(),
91 [&zone, &base](auto const& entry)
92 {
93 try
94 {
95 auto value = zone.template getPropertyValue<int64_t>(
96 entry.first,
97 std::get<intfPos>(entry.second),
98 std::get<propPos>(entry.second));
99 base = std::max(base, value);
100 }
101 catch (const std::out_of_range& oore)
102 {
103 // Property value not found, base request speed unchanged
104 }
105 });
106 // A request speed base of 0 defaults to the current target speed
107 zone.setRequestSpeedBase(base);
108}
109
110Action set_floor_from_average_sensor_value(
111 std::map<int64_t, uint64_t>&& val_to_speed)
112{
113 return [val_to_speed = std::move(val_to_speed)](control::Zone& zone,
114 const Group& group)
115 {
116 auto speed = zone.getDefFloor();
117 if (group.size() != 0)
118 {
119 auto count = 0;
120 auto sumValue = std::accumulate(
121 group.begin(),
122 group.end(),
123 0,
124 [&zone, &count](int64_t sum, auto const& entry)
125 {
126 try
127 {
128 return sum +
129 zone.template getPropertyValue<int64_t>(
130 entry.first,
131 std::get<intfPos>(entry.second),
132 std::get<propPos>(entry.second));
133 }
134 catch (const std::out_of_range& oore)
135 {
136 count++;
137 return sum;
138 }
139 });
140 if ((group.size() - count) > 0)
141 {
142 auto groupSize = static_cast<int64_t>(group.size());
143 auto avgValue = sumValue / (groupSize - count);
144 auto it = std::find_if(
145 val_to_speed.begin(),
146 val_to_speed.end(),
147 [&avgValue](auto const& entry)
148 {
149 return avgValue < entry.first;
150 }
151 );
152 if (it != std::end(val_to_speed))
153 {
154 speed = (*it).second;
155 }
156 }
157 }
158 zone.setFloor(speed);
159 };
160}
161
162Action set_ceiling_from_average_sensor_value(
163 std::map<int64_t, uint64_t>&& val_to_speed)
164{
165 return [val_to_speed = std::move(val_to_speed)](Zone& zone,
166 const Group& group)
167 {
168 auto speed = zone.getCeiling();
169 if (group.size() != 0)
170 {
171 auto count = 0;
172 auto sumValue = std::accumulate(
173 group.begin(),
174 group.end(),
175 0,
176 [&zone, &count](int64_t sum, auto const& entry)
177 {
178 try
179 {
180 return sum +
181 zone.template getPropertyValue<int64_t>(
182 entry.first,
183 std::get<intfPos>(entry.second),
184 std::get<propPos>(entry.second));
185 }
186 catch (const std::out_of_range& oore)
187 {
188 count++;
189 return sum;
190 }
191 });
192 if ((group.size() - count) > 0)
193 {
194 auto groupSize = static_cast<int64_t>(group.size());
195 auto avgValue = sumValue / (groupSize - count);
196 auto prevValue = zone.swapCeilingKeyValue(avgValue);
197 if (avgValue != prevValue)
198 {// Only check if previous and new values differ
199 if (avgValue < prevValue)
200 {// Value is decreasing from previous
201 for (auto it = val_to_speed.rbegin();
202 it != val_to_speed.rend();
203 ++it)
204 {
205 if (it == val_to_speed.rbegin() &&
206 avgValue >= it->first)
207 {
208 // Value is at/above last map key, set
209 // ceiling speed to the last map key's value
210 speed = it->second;
211 break;
212 }
213 else if (std::next(it, 1) == val_to_speed.rend() &&
214 avgValue <= it->first)
215 {
216 // Value is at/below first map key, set
217 // ceiling speed to the first map key's value
218 speed = it->second;
219 break;
220 }
221 if (avgValue < it->first &&
222 it->first <= prevValue)
223 {
224 // Value decreased & transitioned across
225 // a map key, update ceiling speed to this
226 // map key's value when new value is below
227 // map's key and the key is at/below the
228 // previous value
229 speed = it->second;
230 }
231 }
232 }
233 else
234 {// Value is increasing from previous
235 for (auto it = val_to_speed.begin();
236 it != val_to_speed.end();
237 ++it)
238 {
239 if (it == val_to_speed.begin() &&
240 avgValue <= it->first)
241 {
242 // Value is at/below first map key, set
243 // ceiling speed to the first map key's value
244 speed = it->second;
245 break;
246 }
247 else if (std::next(it, 1) == val_to_speed.end() &&
248 avgValue >= it->first)
249 {
250 // Value is at/above last map key, set
251 // ceiling speed to the last map key's value
252 speed = it->second;
253 break;
254 }
255 if (avgValue > it->first &&
256 it->first >= prevValue)
257 {
258 // Value increased & transitioned across
259 // a map key, update ceiling speed to this
260 // map key's value when new value is above
261 // map's key and the key is at/above the
262 // previous value
263 speed = it->second;
264 }
265 }
266 }
267 }
268 }
269 }
270 zone.setCeiling(speed);
271 };
272}
273
274} // namespace action
275} // namespace control
276} // namespace fan
277} // namespace phosphor