xref: /openbmc/phosphor-fan-presence/control/actions.hpp (revision 4fa67aa12bd73f7d528225f0c3c93c3242bbcc23)
117d1fe23SMatthew Barth #pragma once
217d1fe23SMatthew Barth 
33e1bb274SMatthew Barth #include "types.hpp"
43e1bb274SMatthew Barth #include "utility.hpp"
53e1bb274SMatthew Barth #include "zone.hpp"
63e1bb274SMatthew Barth 
717d1fe23SMatthew Barth #include <algorithm>
84af419cdSMatthew Barth #include <numeric>
917d1fe23SMatthew Barth 
1017d1fe23SMatthew Barth namespace phosphor
1117d1fe23SMatthew Barth {
1217d1fe23SMatthew Barth namespace fan
1317d1fe23SMatthew Barth {
1417d1fe23SMatthew Barth namespace control
1517d1fe23SMatthew Barth {
1617d1fe23SMatthew Barth namespace action
1717d1fe23SMatthew Barth {
1817d1fe23SMatthew Barth 
1917d1fe23SMatthew Barth /**
202a646c5fSMatthew Barth  * @brief An action that wraps a list of actions with a timer
212a646c5fSMatthew Barth  * @details Sets up a list of actions to be invoked when the defined timer
222a646c5fSMatthew Barth  * expires (or for each expiration of a repeating timer).
232a646c5fSMatthew Barth  *
242a646c5fSMatthew Barth  * @param[in] tConf - Timer configuration parameters
252a646c5fSMatthew Barth  * @param[in] action - List of actions to be called when the timer expires
262a646c5fSMatthew Barth  *
272a646c5fSMatthew Barth  * @return Action lambda function
282a646c5fSMatthew Barth  *     An Action function that creates a timer
292a646c5fSMatthew Barth  */
303e1bb274SMatthew Barth Action call_actions_based_on_timer(TimerConf&& tConf,
312a646c5fSMatthew Barth                                    std::vector<Action>&& actions);
322a646c5fSMatthew Barth 
332a646c5fSMatthew Barth /**
3498726c45SMatthew Barth  * @brief An action that sets the floor to the default fan floor speed
3598726c45SMatthew Barth  * @details Sets the fan floor to the defined default fan floor speed when a
3698726c45SMatthew Barth  * service associated to the given group has terminated. Once all services
3798726c45SMatthew Barth  * are functional and providing the sensors again, the fan floor is allowed
3898726c45SMatthew Barth  * to be set normally.
3998726c45SMatthew Barth  *
4098726c45SMatthew Barth  * @param[in] zone - Zone containing fans
4198726c45SMatthew Barth  * @param[in] group - Group of sensors to determine services' states
4298726c45SMatthew Barth  */
4398726c45SMatthew Barth void default_floor_on_missing_owner(Zone& zone, const Group& group);
4498726c45SMatthew Barth 
4598726c45SMatthew Barth /**
460decd1bdSMatthew Barth  * @brief An action to set a speed when a service owner is missing
470decd1bdSMatthew Barth  * @details Sets the fans to the given speed when any service owner associated
480decd1bdSMatthew Barth  * to the group is missing. Once all services are functional and providing
490decd1bdSMatthew Barth  * the event data again, active fan speed changes are allowed.
500decd1bdSMatthew Barth  *
510decd1bdSMatthew Barth  * @param[in] speed - Speed to set the zone to
520decd1bdSMatthew Barth  *
530decd1bdSMatthew Barth  * @return Action lambda function
540decd1bdSMatthew Barth  *     An Action function that sets the zone to the given speed if any service
550decd1bdSMatthew Barth  *     owners are missing.
560decd1bdSMatthew Barth  */
570decd1bdSMatthew Barth Action set_speed_on_missing_owner(uint64_t speed);
580decd1bdSMatthew Barth 
590decd1bdSMatthew Barth /**
60b280bfa4SMatthew Barth  * @brief An action to set the request speed base
61b280bfa4SMatthew Barth  * @details A new target speed is determined using a speed delta being added
62b280bfa4SMatthew Barth  * or subtracted, for increases or decrease respectively, from a base speed.
63b280bfa4SMatthew Barth  * This base speed defaults to be the current target speed or is set to a
64b280bfa4SMatthew Barth  * different base speed(i.e. the fans' tach feedback speed) to request a new
65b280bfa4SMatthew Barth  * target from.
66b280bfa4SMatthew Barth  *
67b280bfa4SMatthew Barth  * @param[in] zone - Zone containing fans
68b280bfa4SMatthew Barth  * @param[in] group - Group of sensors to determine base from
69b280bfa4SMatthew Barth  */
70b280bfa4SMatthew Barth void set_request_speed_base_with_max(Zone& zone, const Group& group);
71b280bfa4SMatthew Barth 
72b280bfa4SMatthew Barth /**
7317d1fe23SMatthew Barth  * @brief An action to set the speed on a zone
74861d77c3SMatthew Barth  * @details The zone is held at the given speed when a defined number of
7517d1fe23SMatthew Barth  * properties in the group are set to the given state
7617d1fe23SMatthew Barth  *
7717d1fe23SMatthew Barth  * @param[in] count - Number of properties
7817d1fe23SMatthew Barth  * @param[in] state - Value the property(s) needed to be set at
7917d1fe23SMatthew Barth  * @param[in] speed - Speed to set the zone to
8017d1fe23SMatthew Barth  *
8117d1fe23SMatthew Barth  * @return Lambda function
8217d1fe23SMatthew Barth  *     A lambda function to set the zone speed when the number of properties
8317d1fe23SMatthew Barth  *     within the group are at a certain value
8417d1fe23SMatthew Barth  */
859e741ed0SMatthew Barth template <typename T>
count_state_before_speed(size_t count,T && state,uint64_t speed)869e741ed0SMatthew Barth auto count_state_before_speed(size_t count, T&& state, uint64_t speed)
8717d1fe23SMatthew Barth {
88dfddd648SPatrick Williams     return [count, speed,
89dfddd648SPatrick Williams             state = std::forward<T>(state)](auto& zone, auto& group) {
90e0f67c8bSMatthew Barth         size_t numAtState = 0;
91e0f67c8bSMatthew Barth         for (auto& entry : group)
9217d1fe23SMatthew Barth         {
93bc651609SMatthew Barth             try
94bc651609SMatthew Barth             {
95e0f67c8bSMatthew Barth                 if (zone.template getPropertyValue<T>(
963e1bb274SMatthew Barth                         std::get<pathPos>(entry), std::get<intfPos>(entry),
97146b7390SMatthew Barth                         std::get<propPos>(entry)) == state)
98e0f67c8bSMatthew Barth                 {
99e0f67c8bSMatthew Barth                     numAtState++;
100e0f67c8bSMatthew Barth                 }
101bc651609SMatthew Barth             }
102bc651609SMatthew Barth             catch (const std::out_of_range& oore)
103bc651609SMatthew Barth             {
104bc651609SMatthew Barth                 // Default to property not equal when not found
105bc651609SMatthew Barth             }
10617d1fe23SMatthew Barth             if (numAtState >= count)
10717d1fe23SMatthew Barth             {
10817d1fe23SMatthew Barth                 zone.setSpeed(speed);
109e0f67c8bSMatthew Barth                 break;
110e0f67c8bSMatthew Barth             }
11117d1fe23SMatthew Barth         }
11260b00766SMatthew Barth         // Update group's fan control active allowed based on action results
11360b00766SMatthew Barth         zone.setActiveAllow(&group, !(numAtState >= count));
11417d1fe23SMatthew Barth     };
11517d1fe23SMatthew Barth }
11617d1fe23SMatthew Barth 
1174af419cdSMatthew Barth /**
1184af419cdSMatthew Barth  * @brief An action to set the floor speed on a zone
1194af419cdSMatthew Barth  * @details Based on the average of the defined sensor group values, the floor
1204af419cdSMatthew Barth  * speed is selected from the first map key entry that the average sensor value
1214af419cdSMatthew Barth  * is less than.
1224af419cdSMatthew Barth  *
1234af419cdSMatthew Barth  * @param[in] val_to_speed - Ordered map of sensor value-to-speed
1244af419cdSMatthew Barth  *
125b280bfa4SMatthew Barth  * @return Action lambda function
126b280bfa4SMatthew Barth  *     An Action function to set the zone's floor speed when the average of
1274af419cdSMatthew Barth  *     property values within the group is below the lowest sensor value given
1284af419cdSMatthew Barth  */
1299ca6065cSMatthew Barth template <typename T>
set_floor_from_average_sensor_value(std::map<T,uint64_t> && val_to_speed)1303e1bb274SMatthew Barth Action set_floor_from_average_sensor_value(std::map<T, uint64_t>&& val_to_speed)
1319ca6065cSMatthew Barth {
1329ca6065cSMatthew Barth     return [val_to_speed = std::move(val_to_speed)](control::Zone& zone,
1333e1bb274SMatthew Barth                                                     const Group& group) {
1349ca6065cSMatthew Barth         auto speed = zone.getDefFloor();
1359ca6065cSMatthew Barth         if (group.size() != 0)
1369ca6065cSMatthew Barth         {
1379ca6065cSMatthew Barth             auto count = 0;
138dfddd648SPatrick Williams             auto sumValue = std::accumulate(
139dfddd648SPatrick Williams                 group.begin(), group.end(), 0,
140dfddd648SPatrick Williams                 [&zone, &count](T sum, const auto& entry) {
1419ca6065cSMatthew Barth                     try
1429ca6065cSMatthew Barth                     {
1433e1bb274SMatthew Barth                         return sum + zone.template getPropertyValue<T>(
1449ca6065cSMatthew Barth                                          std::get<pathPos>(entry),
1459ca6065cSMatthew Barth                                          std::get<intfPos>(entry),
1469ca6065cSMatthew Barth                                          std::get<propPos>(entry));
1479ca6065cSMatthew Barth                     }
1489ca6065cSMatthew Barth                     catch (const std::out_of_range& oore)
1499ca6065cSMatthew Barth                     {
1509ca6065cSMatthew Barth                         count++;
1519ca6065cSMatthew Barth                         return sum;
1529ca6065cSMatthew Barth                     }
1539ca6065cSMatthew Barth                 });
1549ca6065cSMatthew Barth             if ((group.size() - count) > 0)
1559ca6065cSMatthew Barth             {
1569ca6065cSMatthew Barth                 auto groupSize = static_cast<int64_t>(group.size());
1579ca6065cSMatthew Barth                 auto avgValue = sumValue / (groupSize - count);
1583e1bb274SMatthew Barth                 auto it = std::find_if(val_to_speed.begin(), val_to_speed.end(),
159dfddd648SPatrick Williams                                        [&avgValue](const auto& entry) {
1609ca6065cSMatthew Barth                                            return avgValue < entry.first;
1613e1bb274SMatthew Barth                                        });
1629ca6065cSMatthew Barth                 if (it != std::end(val_to_speed))
1639ca6065cSMatthew Barth                 {
1649ca6065cSMatthew Barth                     speed = (*it).second;
1659ca6065cSMatthew Barth                 }
1669ca6065cSMatthew Barth             }
1679ca6065cSMatthew Barth         }
1689ca6065cSMatthew Barth         zone.setFloor(speed);
1699ca6065cSMatthew Barth     };
1709ca6065cSMatthew Barth }
1714af419cdSMatthew Barth 
172e0ca13ebSMatthew Barth /**
173e0ca13ebSMatthew Barth  * @brief An action to set the ceiling speed on a zone
174b280bfa4SMatthew Barth  * @details Based on the average of the defined sensor group values, the
175b280bfa4SMatthew Barth  * ceiling speed is selected from the map key transition point that the average
176b280bfa4SMatthew Barth  * sensor value falls within depending on the key values direction from what
177b280bfa4SMatthew Barth  * was previously read.
178e0ca13ebSMatthew Barth  *
179e0ca13ebSMatthew Barth  * @param[in] val_to_speed - Ordered map of sensor value-to-speed transitions
180e0ca13ebSMatthew Barth  *
181b280bfa4SMatthew Barth  * @return Action lambda function
182b280bfa4SMatthew Barth  *     An Action function to set the zone's ceiling speed when the average of
183e0ca13ebSMatthew Barth  *     property values within the group is above(increasing) or
184e0ca13ebSMatthew Barth  *     below(decreasing) the key transition point
185e0ca13ebSMatthew Barth  */
1869ca6065cSMatthew Barth template <typename T>
set_ceiling_from_average_sensor_value(std::map<T,uint64_t> && val_to_speed)187*4fa67aa1SPatrick Williams Action set_ceiling_from_average_sensor_value(
188*4fa67aa1SPatrick Williams     std::map<T, uint64_t>&& val_to_speed)
1899ca6065cSMatthew Barth {
190dfddd648SPatrick Williams     return [val_to_speed =
191dfddd648SPatrick Williams                 std::move(val_to_speed)](Zone& zone, const Group& group) {
1929ca6065cSMatthew Barth         auto speed = zone.getCeiling();
1939ca6065cSMatthew Barth         if (group.size() != 0)
1949ca6065cSMatthew Barth         {
1959ca6065cSMatthew Barth             auto count = 0;
196dfddd648SPatrick Williams             auto sumValue = std::accumulate(
197dfddd648SPatrick Williams                 group.begin(), group.end(), 0,
198dfddd648SPatrick Williams                 [&zone, &count](T sum, const auto& entry) {
1999ca6065cSMatthew Barth                     try
2009ca6065cSMatthew Barth                     {
2013e1bb274SMatthew Barth                         return sum + zone.template getPropertyValue<T>(
2029ca6065cSMatthew Barth                                          std::get<pathPos>(entry),
2039ca6065cSMatthew Barth                                          std::get<intfPos>(entry),
2049ca6065cSMatthew Barth                                          std::get<propPos>(entry));
2059ca6065cSMatthew Barth                     }
2069ca6065cSMatthew Barth                     catch (const std::out_of_range& oore)
2079ca6065cSMatthew Barth                     {
2089ca6065cSMatthew Barth                         count++;
2099ca6065cSMatthew Barth                         return sum;
2109ca6065cSMatthew Barth                     }
2119ca6065cSMatthew Barth                 });
2129ca6065cSMatthew Barth             if ((group.size() - count) > 0)
2139ca6065cSMatthew Barth             {
2149ca6065cSMatthew Barth                 auto groupSize = static_cast<int64_t>(group.size());
2159ca6065cSMatthew Barth                 auto avgValue = sumValue / (groupSize - count);
2169ca6065cSMatthew Barth                 auto prevValue = zone.swapCeilingKeyValue(avgValue);
2179ca6065cSMatthew Barth                 if (avgValue != prevValue)
2189ca6065cSMatthew Barth                 {     // Only check if previous and new values differ
2199ca6065cSMatthew Barth                     if (avgValue < prevValue)
2209ca6065cSMatthew Barth                     { // Value is decreasing from previous
2219ca6065cSMatthew Barth                         for (auto it = val_to_speed.rbegin();
2223e1bb274SMatthew Barth                              it != val_to_speed.rend(); ++it)
2239ca6065cSMatthew Barth                         {
2249ca6065cSMatthew Barth                             if (it == val_to_speed.rbegin() &&
2259ca6065cSMatthew Barth                                 avgValue >= it->first)
2269ca6065cSMatthew Barth                             {
2279ca6065cSMatthew Barth                                 // Value is at/above last map key, set
2289ca6065cSMatthew Barth                                 // ceiling speed to the last map key's value
2299ca6065cSMatthew Barth                                 speed = it->second;
2309ca6065cSMatthew Barth                                 break;
2319ca6065cSMatthew Barth                             }
2329ca6065cSMatthew Barth                             else if (std::next(it, 1) == val_to_speed.rend() &&
2339ca6065cSMatthew Barth                                      avgValue <= it->first)
2349ca6065cSMatthew Barth                             {
2359ca6065cSMatthew Barth                                 // Value is at/below first map key, set
2369ca6065cSMatthew Barth                                 // ceiling speed to the first map key's value
2379ca6065cSMatthew Barth                                 speed = it->second;
2389ca6065cSMatthew Barth                                 break;
2399ca6065cSMatthew Barth                             }
2403e1bb274SMatthew Barth                             if (avgValue < it->first && it->first <= prevValue)
2419ca6065cSMatthew Barth                             {
2429ca6065cSMatthew Barth                                 // Value decreased & transitioned across
2439ca6065cSMatthew Barth                                 // a map key, update ceiling speed to this
2449ca6065cSMatthew Barth                                 // map key's value when new value is below
2459ca6065cSMatthew Barth                                 // map's key and the key is at/below the
2469ca6065cSMatthew Barth                                 // previous value
2479ca6065cSMatthew Barth                                 speed = it->second;
2489ca6065cSMatthew Barth                             }
2499ca6065cSMatthew Barth                         }
2509ca6065cSMatthew Barth                     }
2519ca6065cSMatthew Barth                     else
2529ca6065cSMatthew Barth                     { // Value is increasing from previous
2539ca6065cSMatthew Barth                         for (auto it = val_to_speed.begin();
2543e1bb274SMatthew Barth                              it != val_to_speed.end(); ++it)
2559ca6065cSMatthew Barth                         {
2569ca6065cSMatthew Barth                             if (it == val_to_speed.begin() &&
2579ca6065cSMatthew Barth                                 avgValue <= it->first)
2589ca6065cSMatthew Barth                             {
2599ca6065cSMatthew Barth                                 // Value is at/below first map key, set
2609ca6065cSMatthew Barth                                 // ceiling speed to the first map key's value
2619ca6065cSMatthew Barth                                 speed = it->second;
2629ca6065cSMatthew Barth                                 break;
2639ca6065cSMatthew Barth                             }
2649ca6065cSMatthew Barth                             else if (std::next(it, 1) == val_to_speed.end() &&
2659ca6065cSMatthew Barth                                      avgValue >= it->first)
2669ca6065cSMatthew Barth                             {
2679ca6065cSMatthew Barth                                 // Value is at/above last map key, set
2689ca6065cSMatthew Barth                                 // ceiling speed to the last map key's value
2699ca6065cSMatthew Barth                                 speed = it->second;
2709ca6065cSMatthew Barth                                 break;
2719ca6065cSMatthew Barth                             }
2723e1bb274SMatthew Barth                             if (avgValue > it->first && it->first >= prevValue)
2739ca6065cSMatthew Barth                             {
2749ca6065cSMatthew Barth                                 // Value increased & transitioned across
2759ca6065cSMatthew Barth                                 // a map key, update ceiling speed to this
2769ca6065cSMatthew Barth                                 // map key's value when new value is above
2779ca6065cSMatthew Barth                                 // map's key and the key is at/above the
2789ca6065cSMatthew Barth                                 // previous value
2799ca6065cSMatthew Barth                                 speed = it->second;
2809ca6065cSMatthew Barth                             }
2819ca6065cSMatthew Barth                         }
2829ca6065cSMatthew Barth                     }
2839ca6065cSMatthew Barth                 }
2849ca6065cSMatthew Barth             }
2859ca6065cSMatthew Barth         }
2869ca6065cSMatthew Barth         zone.setCeiling(speed);
2879ca6065cSMatthew Barth     };
2889ca6065cSMatthew Barth }
289e0ca13ebSMatthew Barth 
29024623523SMatthew Barth /**
29124623523SMatthew Barth  * @brief An action to set the speed increase delta and request speed change
29224623523SMatthew Barth  * @details Provides the ability to determine what the net increase delta the
29324623523SMatthew Barth  * zone's fan speeds should be updated by from their current target speed and
29424623523SMatthew Barth  * request that new target speed.
29524623523SMatthew Barth  *
29624623523SMatthew Barth  * @param[in] state - State to compare the group's property value to
297172f3936SMatthew Barth  * @param[in] factor - Factor to apply to the calculated net delta
29824623523SMatthew Barth  * @param[in] speedDelta - Speed delta of the group
29924623523SMatthew Barth  *
30024623523SMatthew Barth  * @return Lambda function
30124623523SMatthew Barth  *     A lambda function that determines the net increase delta and requests
30224623523SMatthew Barth  * a new target speed with that increase for the zone.
30324623523SMatthew Barth  */
30424623523SMatthew Barth template <typename T>
set_net_increase_speed(T && state,T && factor,uint64_t speedDelta)305172f3936SMatthew Barth auto set_net_increase_speed(T&& state, T&& factor, uint64_t speedDelta)
30624623523SMatthew Barth {
3073e1bb274SMatthew Barth     return [speedDelta, factor = std::forward<T>(factor),
3083e1bb274SMatthew Barth             state = std::forward<T>(state)](auto& zone, auto& group) {
30924623523SMatthew Barth         auto netDelta = zone.getIncSpeedDelta();
310dfddd648SPatrick Williams         std::for_each(
311dfddd648SPatrick Williams             group.begin(), group.end(),
3123e1bb274SMatthew Barth             [&zone, &state, &factor, &speedDelta,
313dfddd648SPatrick Williams              &netDelta](const auto& entry) {
314bc651609SMatthew Barth                 try
31524623523SMatthew Barth                 {
31624623523SMatthew Barth                     T value = zone.template getPropertyValue<T>(
3173e1bb274SMatthew Barth                         std::get<pathPos>(entry), std::get<intfPos>(entry),
318146b7390SMatthew Barth                         std::get<propPos>(entry));
31924623523SMatthew Barth                     // TODO openbmc/phosphor-fan-presence#7 - Support possible
32024623523SMatthew Barth                     // state types for comparison
32124623523SMatthew Barth                     if (value >= state)
32224623523SMatthew Barth                     {
323172f3936SMatthew Barth                         // Increase by at least a single delta(factor)
32424623523SMatthew Barth                         // to attempt bringing under 'state'
3253e1bb274SMatthew Barth                         auto delta = std::max((value - state), factor);
326172f3936SMatthew Barth                         // Increase is the factor applied to the
327172f3936SMatthew Barth                         // difference times the given speed delta
328dfddd648SPatrick Williams                         netDelta = std::max(netDelta,
329dfddd648SPatrick Williams                                             static_cast<uint64_t>(
330dfddd648SPatrick Williams                                                 (delta / factor) * speedDelta));
33124623523SMatthew Barth                     }
33224623523SMatthew Barth                 }
333bc651609SMatthew Barth                 catch (const std::out_of_range& oore)
334bc651609SMatthew Barth                 {
335bc651609SMatthew Barth                     // Property value not found, netDelta unchanged
336bc651609SMatthew Barth                 }
3373e1bb274SMatthew Barth             });
338240397b9SMatthew Barth         // Request speed change for target speed update
339240397b9SMatthew Barth         zone.requestSpeedIncrease(netDelta);
34024623523SMatthew Barth     };
34124623523SMatthew Barth }
34224623523SMatthew Barth 
3430ce99d8bSMatthew Barth /**
3440ce99d8bSMatthew Barth  * @brief An action to set the speed decrease delta and request speed change
3450ce99d8bSMatthew Barth  * @details Provides the ability to determine what the net decrease delta each
3460ce99d8bSMatthew Barth  * zone's fan speeds should be updated by from their current target speed, and
3470ce99d8bSMatthew Barth  * request that speed change occur on the next decrease interval.
3480ce99d8bSMatthew Barth  *
3490ce99d8bSMatthew Barth  * @param[in] state - State to compare the group's property value to
350172f3936SMatthew Barth  * @param[in] factor - Factor to apply to the calculated net delta
3510ce99d8bSMatthew Barth  * @param[in] speedDelta - Speed delta of the group
3520ce99d8bSMatthew Barth  *
3530ce99d8bSMatthew Barth  * @return Lambda function
3540ce99d8bSMatthew Barth  *     A lambda function that determines the net decrease delta and requests
3550ce99d8bSMatthew Barth  * a new target speed with that decrease for the zone.
3560ce99d8bSMatthew Barth  */
3570ce99d8bSMatthew Barth template <typename T>
set_net_decrease_speed(T && state,T && factor,uint64_t speedDelta)358172f3936SMatthew Barth auto set_net_decrease_speed(T&& state, T&& factor, uint64_t speedDelta)
3590ce99d8bSMatthew Barth {
3603e1bb274SMatthew Barth     return [speedDelta, factor = std::forward<T>(factor),
3613e1bb274SMatthew Barth             state = std::forward<T>(state)](auto& zone, auto& group) {
3620ce99d8bSMatthew Barth         auto netDelta = zone.getDecSpeedDelta();
363e4338cdbSMatthew Barth         for (auto& entry : group)
3640ce99d8bSMatthew Barth         {
365bc651609SMatthew Barth             try
366bc651609SMatthew Barth             {
3670ce99d8bSMatthew Barth                 T value = zone.template getPropertyValue<T>(
3683e1bb274SMatthew Barth                     std::get<pathPos>(entry), std::get<intfPos>(entry),
369146b7390SMatthew Barth                     std::get<propPos>(entry));
3700ce99d8bSMatthew Barth                 // TODO openbmc/phosphor-fan-presence#7 - Support possible
3710ce99d8bSMatthew Barth                 // state types for comparison
3720ce99d8bSMatthew Barth                 if (value < state)
3730ce99d8bSMatthew Barth                 {
3740ce99d8bSMatthew Barth                     if (netDelta == 0)
3750ce99d8bSMatthew Barth                     {
376172f3936SMatthew Barth                         netDelta = ((state - value) / factor) * speedDelta;
3770ce99d8bSMatthew Barth                     }
3780ce99d8bSMatthew Barth                     else
3790ce99d8bSMatthew Barth                     {
380172f3936SMatthew Barth                         // Decrease is the factor applied to the
381172f3936SMatthew Barth                         // difference times the given speed delta
382172f3936SMatthew Barth                         netDelta = std::min(
383172f3936SMatthew Barth                             netDelta,
384dfddd648SPatrick Williams                             static_cast<uint64_t>(
385dfddd648SPatrick Williams                                 ((state - value) / factor) * speedDelta));
3860ce99d8bSMatthew Barth                     }
3870ce99d8bSMatthew Barth                 }
388e4338cdbSMatthew Barth                 else
389e4338cdbSMatthew Barth                 {
390e4338cdbSMatthew Barth                     // No decrease allowed for this group
391e4338cdbSMatthew Barth                     netDelta = 0;
392e4338cdbSMatthew Barth                     break;
393e4338cdbSMatthew Barth                 }
3940ce99d8bSMatthew Barth             }
395bc651609SMatthew Barth             catch (const std::out_of_range& oore)
396bc651609SMatthew Barth             {
397bc651609SMatthew Barth                 // Property value not found, netDelta unchanged
398bc651609SMatthew Barth             }
399bc651609SMatthew Barth         }
400e4338cdbSMatthew Barth         // Update group's decrease allowed state
401e4338cdbSMatthew Barth         zone.setDecreaseAllow(&group, !(netDelta == 0));
4020ce99d8bSMatthew Barth         // Request speed decrease to occur on decrease interval
4030ce99d8bSMatthew Barth         zone.requestSpeedDecrease(netDelta);
4040ce99d8bSMatthew Barth     };
4050ce99d8bSMatthew Barth }
4060ce99d8bSMatthew Barth 
407c410ddabSMatthew Barth /**
408c410ddabSMatthew Barth  * @brief An action to use an alternate set of events
409c410ddabSMatthew Barth  * @details Provides the ability to replace a default set of events with an
410c410ddabSMatthew Barth  * alternate set of events based on all members of a group being at a specified
411c410ddabSMatthew Barth  * state. When any member of the group no longer matches the provided state,
412c410ddabSMatthew Barth  * the alternate set of events are replaced with the defaults.
413c410ddabSMatthew Barth  *
414c410ddabSMatthew Barth  * @param[in] state - State to compare the group's property value to
415c410ddabSMatthew Barth  * @param[in] defEvents - The default set of events
416c410ddabSMatthew Barth  * @param[in] altEvents - The alternate set of events
417c410ddabSMatthew Barth  *
418c410ddabSMatthew Barth  * @return Lambda function
419c410ddabSMatthew Barth  *     A lambda function that checks all group members are at a specified state
420c410ddabSMatthew Barth  * and replacing the default set of events with an alternate set of events.
421c410ddabSMatthew Barth  */
422c410ddabSMatthew Barth template <typename T>
use_alternate_events_on_state(T && state,std::vector<SetSpeedEvent> && defEvents,std::vector<SetSpeedEvent> && altEvents)423c410ddabSMatthew Barth auto use_alternate_events_on_state(T&& state,
424c410ddabSMatthew Barth                                    std::vector<SetSpeedEvent>&& defEvents,
425c410ddabSMatthew Barth                                    std::vector<SetSpeedEvent>&& altEvents)
426c410ddabSMatthew Barth {
4273e1bb274SMatthew Barth     return [state = std::forward<T>(state), defEvents = std::move(defEvents),
4283e1bb274SMatthew Barth             altEvents = std::move(altEvents)](auto& zone, auto& group) {
429c410ddabSMatthew Barth         // Compare all group entries to the state
430dfddd648SPatrick Williams         auto useAlt = std::all_of(
431dfddd648SPatrick Williams             group.begin(), group.end(), [&zone, &state](const auto& entry) {
432c410ddabSMatthew Barth                 try
433c410ddabSMatthew Barth                 {
434c410ddabSMatthew Barth                     return zone.template getPropertyValue<T>(
435dfddd648SPatrick Williams                                std::get<pathPos>(entry),
436dfddd648SPatrick Williams                                std::get<intfPos>(entry),
437146b7390SMatthew Barth                                std::get<propPos>(entry)) == state;
438c410ddabSMatthew Barth                 }
439c410ddabSMatthew Barth                 catch (const std::out_of_range& oore)
440c410ddabSMatthew Barth                 {
441c410ddabSMatthew Barth                     // Default to property not equal when not found
442c410ddabSMatthew Barth                     return false;
443c410ddabSMatthew Barth                 }
444c410ddabSMatthew Barth             });
445c410ddabSMatthew Barth 
446c410ddabSMatthew Barth         const std::vector<SetSpeedEvent>* rmEvents = &altEvents;
447c410ddabSMatthew Barth         const std::vector<SetSpeedEvent>* initEvents = &defEvents;
448c410ddabSMatthew Barth 
449c410ddabSMatthew Barth         if (useAlt)
450c410ddabSMatthew Barth         {
451c410ddabSMatthew Barth             rmEvents = &defEvents;
452c410ddabSMatthew Barth             initEvents = &altEvents;
453c410ddabSMatthew Barth         }
454c410ddabSMatthew Barth 
455c410ddabSMatthew Barth         // Remove events
4563e1bb274SMatthew Barth         std::for_each(rmEvents->begin(), rmEvents->end(),
457dfddd648SPatrick Williams                       [&zone](const auto& entry) { zone.removeEvent(entry); });
458c410ddabSMatthew Barth         // Init events
4593e1bb274SMatthew Barth         std::for_each(initEvents->begin(), initEvents->end(),
460dfddd648SPatrick Williams                       [&zone](const auto& entry) { zone.initEvent(entry); });
461c410ddabSMatthew Barth     };
462c410ddabSMatthew Barth }
463c410ddabSMatthew Barth 
464014f07c7SMatthew Barth /**
465014f07c7SMatthew Barth  * @brief An action to set the floor speed on a zone
466014f07c7SMatthew Barth  * @details Using sensor group values that are within a defined range, the
467014f07c7SMatthew Barth  * floor speed is selected from the first map key entry that the median
468014f07c7SMatthew Barth  * sensor value is less than where 3 or more sensor group values are valid.
469014f07c7SMatthew Barth  * In the case where less than 3 sensor values are valid, use the highest
470014f07c7SMatthew Barth  * sensor group value and default the floor speed when 0 sensor group values
471014f07c7SMatthew Barth  * are valid.
472014f07c7SMatthew Barth  *
473014f07c7SMatthew Barth  * @param[in] lowerBound - Lowest allowed sensor value to be valid
474014f07c7SMatthew Barth  * @param[in] upperBound - Highest allowed sensor value to be valid
475014f07c7SMatthew Barth  * @param[in] valueToSpeed - Ordered map of sensor value-to-speed
476014f07c7SMatthew Barth  *
477014f07c7SMatthew Barth  * @return Action lambda function
478014f07c7SMatthew Barth  *     An Action function to set the zone's floor speed from a resulting group
479014f07c7SMatthew Barth  * of valid sensor values based on their highest value or median.
480014f07c7SMatthew Barth  */
4819ca6065cSMatthew Barth template <typename T>
set_floor_from_median_sensor_value(T && lowerBound,T && upperBound,std::map<T,uint64_t> && valueToSpeed)4823e1bb274SMatthew Barth Action set_floor_from_median_sensor_value(T&& lowerBound, T&& upperBound,
4839ca6065cSMatthew Barth                                           std::map<T, uint64_t>&& valueToSpeed)
4849ca6065cSMatthew Barth {
4859ca6065cSMatthew Barth     return [lowerBound = std::forward<T>(lowerBound),
4869ca6065cSMatthew Barth             upperBound = std::forward<T>(upperBound),
4879ca6065cSMatthew Barth             valueToSpeed = std::move(valueToSpeed)](control::Zone& zone,
4883e1bb274SMatthew Barth                                                     const Group& group) {
4899ca6065cSMatthew Barth         auto speed = zone.getDefFloor();
4909ca6065cSMatthew Barth         if (group.size() != 0)
4919ca6065cSMatthew Barth         {
4929ca6065cSMatthew Barth             std::vector<T> validValues;
493dfddd648SPatrick Williams             for (const auto& member : group)
4949ca6065cSMatthew Barth             {
4959ca6065cSMatthew Barth                 try
4969ca6065cSMatthew Barth                 {
4979ca6065cSMatthew Barth                     auto value = zone.template getPropertyValue<T>(
4983e1bb274SMatthew Barth                         std::get<pathPos>(member), std::get<intfPos>(member),
4999ca6065cSMatthew Barth                         std::get<propPos>(member));
5009ca6065cSMatthew Barth                     if (value == std::clamp(value, lowerBound, upperBound))
5019ca6065cSMatthew Barth                     {
5029ca6065cSMatthew Barth                         // Sensor value is valid
5039ca6065cSMatthew Barth                         validValues.emplace_back(value);
5049ca6065cSMatthew Barth                     }
5059ca6065cSMatthew Barth                 }
5069ca6065cSMatthew Barth                 catch (const std::out_of_range& oore)
5079ca6065cSMatthew Barth                 {
5089ca6065cSMatthew Barth                     continue;
5099ca6065cSMatthew Barth                 }
5109ca6065cSMatthew Barth             }
5119ca6065cSMatthew Barth 
5129ca6065cSMatthew Barth             if (!validValues.empty())
5139ca6065cSMatthew Barth             {
5149ca6065cSMatthew Barth                 auto median = validValues.front();
5159ca6065cSMatthew Barth                 // Get the determined median value
5169ca6065cSMatthew Barth                 if (validValues.size() == 2)
5179ca6065cSMatthew Barth                 {
5189ca6065cSMatthew Barth                     // For 2 values, use the highest instead of the average
5199ca6065cSMatthew Barth                     // for a thermally safe floor
5209ca6065cSMatthew Barth                     median = *std::max_element(validValues.begin(),
5219ca6065cSMatthew Barth                                                validValues.end());
5229ca6065cSMatthew Barth                 }
5239ca6065cSMatthew Barth                 else if (validValues.size() > 2)
5249ca6065cSMatthew Barth                 {
5259ca6065cSMatthew Barth                     median = utility::getMedian(validValues);
5269ca6065cSMatthew Barth                 }
5279ca6065cSMatthew Barth 
5289ca6065cSMatthew Barth                 // Use determined median sensor value to find floor speed
5293e1bb274SMatthew Barth                 auto it = std::find_if(valueToSpeed.begin(), valueToSpeed.end(),
530dfddd648SPatrick Williams                                        [&median](const auto& entry) {
5319ca6065cSMatthew Barth                                            return median < entry.first;
5323e1bb274SMatthew Barth                                        });
5339ca6065cSMatthew Barth                 if (it != std::end(valueToSpeed))
5349ca6065cSMatthew Barth                 {
5359ca6065cSMatthew Barth                     speed = (*it).second;
5369ca6065cSMatthew Barth                 }
5379ca6065cSMatthew Barth             }
5389ca6065cSMatthew Barth         }
5399ca6065cSMatthew Barth         zone.setFloor(speed);
5409ca6065cSMatthew Barth     };
5419ca6065cSMatthew Barth }
542014f07c7SMatthew Barth 
5438d06a838SMatthew Barth /**
5448d06a838SMatthew Barth  * @brief An action to update the default floor speed
5458d06a838SMatthew Barth  * @details Provides the ability to update the default fan floor speed when
5468d06a838SMatthew Barth  * all of the group members property values match the value given
5478d06a838SMatthew Barth  *
5488d06a838SMatthew Barth  * @param[in] state - State to compare the group's property value to
5498d06a838SMatthew Barth  * @param[in] speed - Speed to set the default fan floor to
5508d06a838SMatthew Barth  *
5518d06a838SMatthew Barth  * @return Lambda function
5528d06a838SMatthew Barth  *     A lambda function that checks all group members are at a specified state
5538d06a838SMatthew Barth  * and updates the default fan floor speed.
5548d06a838SMatthew Barth  */
5558d06a838SMatthew Barth template <typename T>
update_default_floor(T && state,uint64_t speed)5568d06a838SMatthew Barth auto update_default_floor(T&& state, uint64_t speed)
5578d06a838SMatthew Barth {
5583e1bb274SMatthew Barth     return [speed, state = std::forward<T>(state)](auto& zone, auto& group) {
559dfddd648SPatrick Williams         auto updateDefFloor = std::all_of(
560dfddd648SPatrick Williams             group.begin(), group.end(), [&zone, &state](const auto& entry) {
5618d06a838SMatthew Barth                 try
5628d06a838SMatthew Barth                 {
5638d06a838SMatthew Barth                     return zone.template getPropertyValue<T>(
564dfddd648SPatrick Williams                                std::get<pathPos>(entry),
565dfddd648SPatrick Williams                                std::get<intfPos>(entry),
5668d06a838SMatthew Barth                                std::get<propPos>(entry)) == state;
5678d06a838SMatthew Barth                 }
5688d06a838SMatthew Barth                 catch (const std::out_of_range& oore)
5698d06a838SMatthew Barth                 {
5708d06a838SMatthew Barth                     // Default to property not equal when not found
5718d06a838SMatthew Barth                     return false;
5728d06a838SMatthew Barth                 }
5738d06a838SMatthew Barth             });
5748d06a838SMatthew Barth 
5758d06a838SMatthew Barth         if (!updateDefFloor)
5768d06a838SMatthew Barth         {
5778d06a838SMatthew Barth             // Do not update the default floor
5788d06a838SMatthew Barth             return;
5798d06a838SMatthew Barth         }
5808d06a838SMatthew Barth 
5818d06a838SMatthew Barth         // Set/update the default floor of the zone
5828d06a838SMatthew Barth         zone.setDefFloor(speed);
5838d06a838SMatthew Barth     };
5848d06a838SMatthew Barth }
5858d06a838SMatthew Barth 
586799cdf74SMatthew Barth /**
587799cdf74SMatthew Barth  * @brief An action to use a set of events
588799cdf74SMatthew Barth  * @details Provides the ability to use a set of events when all members of
589799cdf74SMatthew Barth  * a group are at a specified state. When any member of the group no longer
590799cdf74SMatthew Barth  * matches the provided state the set of events are removed.
591799cdf74SMatthew Barth  *
592799cdf74SMatthew Barth  * @param[in] state - State to compare the group's property value to
593799cdf74SMatthew Barth  * @param[in] events - The set of events
594799cdf74SMatthew Barth  *
595799cdf74SMatthew Barth  * @return Lambda function
596799cdf74SMatthew Barth  *     A lambda function that checks all group members are at a specified state
597799cdf74SMatthew Barth  * and initializes the set of events, otherwise removes them.
598799cdf74SMatthew Barth  */
599799cdf74SMatthew Barth template <typename T>
use_events_on_state(T && state,std::vector<SetSpeedEvent> && events)6003e1bb274SMatthew Barth auto use_events_on_state(T&& state, std::vector<SetSpeedEvent>&& events)
601799cdf74SMatthew Barth {
602799cdf74SMatthew Barth     return [state = std::forward<T>(state),
6033e1bb274SMatthew Barth             events = std::move(events)](auto& zone, auto& group) {
604799cdf74SMatthew Barth         // Compare all group entries to the state
605dfddd648SPatrick Williams         auto useEvents = std::all_of(
606dfddd648SPatrick Williams             group.begin(), group.end(), [&zone, &state](const auto& entry) {
607799cdf74SMatthew Barth                 try
608799cdf74SMatthew Barth                 {
609799cdf74SMatthew Barth                     return zone.template getPropertyValue<T>(
610dfddd648SPatrick Williams                                std::get<pathPos>(entry),
611dfddd648SPatrick Williams                                std::get<intfPos>(entry),
612799cdf74SMatthew Barth                                std::get<propPos>(entry)) == state;
613799cdf74SMatthew Barth                 }
614799cdf74SMatthew Barth                 catch (const std::out_of_range& oore)
615799cdf74SMatthew Barth                 {
616799cdf74SMatthew Barth                     // Default to property not equal when not found
617799cdf74SMatthew Barth                     return false;
618799cdf74SMatthew Barth                 }
619799cdf74SMatthew Barth             });
620799cdf74SMatthew Barth 
621799cdf74SMatthew Barth         if (useEvents)
622799cdf74SMatthew Barth         {
623799cdf74SMatthew Barth             // Init events
624dfddd648SPatrick Williams             std::for_each(events.begin(), events.end(),
625dfddd648SPatrick Williams                           [&zone](const auto& entry) {
626dfddd648SPatrick Williams                               zone.initEvent(entry);
627dfddd648SPatrick Williams                           });
628799cdf74SMatthew Barth         }
629799cdf74SMatthew Barth         else
630799cdf74SMatthew Barth         {
631799cdf74SMatthew Barth             // Remove events
632dfddd648SPatrick Williams             std::for_each(events.begin(), events.end(),
633dfddd648SPatrick Williams                           [&zone](const auto& entry) {
634dfddd648SPatrick Williams                               zone.removeEvent(entry);
635dfddd648SPatrick Williams                           });
636799cdf74SMatthew Barth         }
637799cdf74SMatthew Barth     };
638799cdf74SMatthew Barth }
639799cdf74SMatthew Barth 
64017d1fe23SMatthew Barth } // namespace action
64117d1fe23SMatthew Barth } // namespace control
64217d1fe23SMatthew Barth } // namespace fan
64317d1fe23SMatthew Barth } // namespace phosphor
644