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