1 #include "actions.hpp"
2 
3 namespace phosphor
4 {
5 namespace fan
6 {
7 namespace control
8 {
9 namespace action
10 {
11 
12 using namespace phosphor::fan;
13 
14 Action 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                             group,
39                             "",
40                             nullptr,
41                             actions
42                     );
43                 // Create/start timer and associate event data with it
44                 std::unique_ptr<util::Timer> timer =
45                     std::make_unique<util::Timer>(
46                             zone.getEventPtr(),
47                             [&zone,
48                             actions = &actions,
49                             group = &group]()
50                             {
51                                 zone.timerExpired(*group, *actions);
52                             });
53                 if (!timer->running())
54                 {
55                     timer->start(std::get<intervalPos>(tConf),
56                                  std::get<typePos>(tConf));
57                 }
58                 zone.addTimer(std::move(eventData), std::move(timer));
59             }
60             else
61             {
62                 // Stop and remove any timers for this group
63                 auto timer = zone.findTimer(group, actions);
64                 if (timer != std::end(zone.getTimerEvents()))
65                 {
66                     if (std::get<timerTimerPos>(*timer)->running())
67                     {
68                         std::get<timerTimerPos>(*timer)->stop();
69                     }
70                     zone.removeTimer(timer);
71                 }
72             }
73         }
74         catch (const std::out_of_range& oore)
75         {
76             // Group not found, no timers set
77         }
78     };
79 }
80 
81 void default_floor_on_missing_owner(Zone& zone, const Group& group)
82 {
83     // Set/update the services of the group
84     zone.setServices(&group);
85     auto services = zone.getGroupServices(&group);
86     auto defFloor = std::any_of(
87         services.begin(),
88         services.end(),
89         [](const auto& s)
90         {
91             return !std::get<hasOwnerPos>(s);
92         });
93     if (defFloor)
94     {
95         zone.setFloor(zone.getDefFloor());
96     }
97     // Update fan control floor change allowed
98     zone.setFloorChangeAllow(&group, !defFloor);
99 }
100 
101 Action set_speed_on_missing_owner(uint64_t speed)
102 {
103     return [speed](control::Zone& zone, const Group& group)
104     {
105         // Set/update the services of the group
106         zone.setServices(&group);
107         auto services = zone.getGroupServices(&group);
108         auto missingOwner = std::any_of(
109             services.begin(),
110             services.end(),
111             [](const auto& s)
112             {
113                 return !std::get<hasOwnerPos>(s);
114             });
115         if (missingOwner)
116         {
117             zone.setSpeed(speed);
118         }
119         // Update group's fan control active allowed based on action results
120         zone.setActiveAllow(&group, !missingOwner);
121     };
122 }
123 
124 void set_request_speed_base_with_max(control::Zone& zone,
125                                      const Group& group)
126 {
127     int64_t base = 0;
128     std::for_each(
129             group.begin(),
130             group.end(),
131             [&zone, &base](auto const& entry)
132         {
133             try
134             {
135                 auto value = zone.template getPropertyValue<int64_t>(
136                         entry.first,
137                         std::get<intfPos>(entry.second),
138                         std::get<propPos>(entry.second));
139                 base = std::max(base, value);
140             }
141             catch (const std::out_of_range& oore)
142             {
143                 // Property value not found, base request speed unchanged
144             }
145         });
146     // A request speed base of 0 defaults to the current target speed
147     zone.setRequestSpeedBase(base);
148 }
149 
150 Action set_floor_from_average_sensor_value(
151         std::map<int64_t, uint64_t>&& val_to_speed)
152 {
153     return [val_to_speed = std::move(val_to_speed)](control::Zone& zone,
154                                                     const Group& group)
155     {
156         auto speed = zone.getDefFloor();
157         if (group.size() != 0)
158         {
159             auto count = 0;
160             auto sumValue = std::accumulate(
161                     group.begin(),
162                     group.end(),
163                     0,
164                     [&zone, &count](int64_t sum, auto const& entry)
165                     {
166                         try
167                         {
168                             return sum +
169                                 zone.template getPropertyValue<int64_t>(
170                                     entry.first,
171                                     std::get<intfPos>(entry.second),
172                                     std::get<propPos>(entry.second));
173                         }
174                         catch (const std::out_of_range& oore)
175                         {
176                             count++;
177                             return sum;
178                         }
179                     });
180             if ((group.size() - count) > 0)
181             {
182                 auto groupSize = static_cast<int64_t>(group.size());
183                 auto avgValue = sumValue / (groupSize - count);
184                 auto it = std::find_if(
185                     val_to_speed.begin(),
186                     val_to_speed.end(),
187                     [&avgValue](auto const& entry)
188                     {
189                         return avgValue < entry.first;
190                     }
191                 );
192                 if (it != std::end(val_to_speed))
193                 {
194                     speed = (*it).second;
195                 }
196             }
197         }
198         zone.setFloor(speed);
199     };
200 }
201 
202 Action set_ceiling_from_average_sensor_value(
203         std::map<int64_t, uint64_t>&& val_to_speed)
204 {
205     return [val_to_speed = std::move(val_to_speed)](Zone& zone,
206                                                     const Group& group)
207     {
208         auto speed = zone.getCeiling();
209         if (group.size() != 0)
210         {
211             auto count = 0;
212             auto sumValue = std::accumulate(
213                     group.begin(),
214                     group.end(),
215                     0,
216                     [&zone, &count](int64_t sum, auto const& entry)
217                     {
218                         try
219                         {
220                             return sum +
221                                 zone.template getPropertyValue<int64_t>(
222                                     entry.first,
223                                     std::get<intfPos>(entry.second),
224                                     std::get<propPos>(entry.second));
225                         }
226                         catch (const std::out_of_range& oore)
227                         {
228                             count++;
229                             return sum;
230                         }
231                     });
232             if ((group.size() - count) > 0)
233             {
234                 auto groupSize = static_cast<int64_t>(group.size());
235                 auto avgValue = sumValue / (groupSize - count);
236                 auto prevValue = zone.swapCeilingKeyValue(avgValue);
237                 if (avgValue != prevValue)
238                 {// Only check if previous and new values differ
239                     if (avgValue < prevValue)
240                     {// Value is decreasing from previous
241                         for (auto it = val_to_speed.rbegin();
242                              it != val_to_speed.rend();
243                              ++it)
244                         {
245                             if (it == val_to_speed.rbegin() &&
246                                 avgValue >= it->first)
247                             {
248                                 // Value is at/above last map key, set
249                                 // ceiling speed to the last map key's value
250                                 speed = it->second;
251                                 break;
252                             }
253                             else if (std::next(it, 1) == val_to_speed.rend() &&
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                             if (avgValue < it->first &&
262                                 it->first <= prevValue)
263                             {
264                                 // Value decreased & transitioned across
265                                 // a map key, update ceiling speed to this
266                                 // map key's value when new value is below
267                                 // map's key and the key is at/below the
268                                 // previous value
269                                 speed = it->second;
270                             }
271                         }
272                     }
273                     else
274                     {// Value is increasing from previous
275                         for (auto it = val_to_speed.begin();
276                              it != val_to_speed.end();
277                              ++it)
278                         {
279                             if (it == val_to_speed.begin() &&
280                                 avgValue <= it->first)
281                             {
282                                 // Value is at/below first map key, set
283                                 // ceiling speed to the first map key's value
284                                 speed = it->second;
285                                 break;
286                             }
287                             else if (std::next(it, 1) == val_to_speed.end() &&
288                                      avgValue >= it->first)
289                             {
290                                 // Value is at/above last map key, set
291                                 // ceiling speed to the last map key's value
292                                 speed = it->second;
293                                 break;
294                             }
295                             if (avgValue > it->first &&
296                                 it->first >= prevValue)
297                             {
298                                 // Value increased & transitioned across
299                                 // a map key, update ceiling speed to this
300                                 // map key's value when new value is above
301                                 // map's key and the key is at/above the
302                                 // previous value
303                                 speed = it->second;
304                             }
305                         }
306                     }
307                 }
308             }
309         }
310         zone.setCeiling(speed);
311     };
312 }
313 
314 } // namespace action
315 } // namespace control
316 } // namespace fan
317 } // namespace phosphor
318