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(TimerConf&& tConf,
15                                    std::vector<Action>&& actions)
16 {
17     return [tConf = std::move(tConf),
18             actions = std::move(actions)](control::Zone& zone,
19                                           const Group& group)
20     {
21         try
22         {
23             auto it = zone.getTimerEvents().find(__func__);
24             if (it != zone.getTimerEvents().end())
25             {
26                 auto& timers = it->second;
27                 auto timerIter = zone.findTimer(group, actions, timers);
28                 if (timerIter == timers.end())
29                 {
30                     // No timer exists yet for action, add timer
31                     zone.addTimer(__func__, group, actions, tConf);
32                 }
33                 else if (timerIter != timers.end())
34                 {
35                     // Remove any timer for this group
36                     timers.erase(timerIter);
37                     if (timers.empty())
38                     {
39                         zone.getTimerEvents().erase(it);
40                     }
41                 }
42             }
43             else
44             {
45                 // No timer exists yet for event, add timer
46                 zone.addTimer(__func__, group, actions, tConf);
47             }
48         }
49         catch (const std::out_of_range& oore)
50         {
51             // Group not found, no timers set
52         }
53     };
54 }
55 
56 void default_floor_on_missing_owner(Zone& zone, const Group& group)
57 {
58     // Set/update the services of the group
59     zone.setServices(&group);
60     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 
76 Action set_speed_on_missing_owner(uint64_t speed)
77 {
78     return [speed](control::Zone& zone, const Group& group)
79     {
80         // Set/update the services of the group
81         zone.setServices(&group);
82         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 
99 void 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>(
111                         std::get<pathPos>(entry),
112                         std::get<intfPos>(entry),
113                         std::get<propPos>(entry));
114                 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 
125 Action 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>(
145                                     std::get<pathPos>(entry),
146                                     std::get<intfPos>(entry),
147                                     std::get<propPos>(entry));
148                         }
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 
177 Action 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>(
197                                     std::get<pathPos>(entry),
198                                     std::get<intfPos>(entry),
199                                     std::get<propPos>(entry));
200                         }
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
293