Enable setting/adjusting fan ceiling speed
Set the default ceiling to be what's given as full speed and adjust the
ceiling speed based on an average of a given set of sensor values.
The ceiling is chosen from a given map's key transition values. The map
consists of key, value pairs where each key is the sensor value
transition point and the value is the ceiling speed for when that
transition occurs. The previous key value is needed to determine the
direction in which to chose the appropriate ceiling speed allowing a
buffer zone between ceiling changes if defined to.
Resolves openbmc/openbmc#1628
Change-Id: I7c9c553b5d0c3219c51b563aec7dd5d5f090916b
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/actions.hpp b/control/actions.hpp
index a99fa97..4393c4d 100644
--- a/control/actions.hpp
+++ b/control/actions.hpp
@@ -100,6 +100,115 @@
};
}
+/**
+ * @brief An action to set the ceiling speed on a zone
+ * @details Based on the average of the defined sensor group values, the ceiling
+ * speed is selected from the map key transition point that the average sensor
+ * value falls within depending on the key values direction from what was
+ * previously read.
+ *
+ * @param[in] val_to_speed - Ordered map of sensor value-to-speed transitions
+ *
+ * @return Lambda function
+ * A lambda function to set the zone's ceiling speed when the average of
+ * property values within the group is above(increasing) or
+ * below(decreasing) the key transition point
+ */
+auto set_ceiling_from_average_sensor_value(
+ std::map<int64_t, uint64_t>&& val_to_speed)
+{
+ return [val_to_speed = std::move(val_to_speed)](auto& zone, auto& group)
+ {
+ auto speed = zone.getCeiling();
+ if (group.size() != 0)
+ {
+ auto sumValue = std::accumulate(
+ group.begin(),
+ group.end(),
+ 0,
+ [&zone](int64_t sum, auto const& entry)
+ {
+ return sum + zone.template getPropertyValue<int64_t>(
+ entry.first,
+ std::get<intfPos>(entry.second),
+ std::get<propPos>(entry.second));
+ });
+ auto avgValue = sumValue / group.size();
+ auto prevValue = zone.swapCeilingKeyValue(avgValue);
+ if (avgValue != prevValue)
+ {// Only check if previous and new values differ
+ if (avgValue < prevValue)
+ {// Value is decreasing from previous
+ for (auto it = val_to_speed.rbegin();
+ it != val_to_speed.rend();
+ ++it)
+ {
+ if (it == val_to_speed.rbegin() &&
+ avgValue >= it->first)
+ {
+ // Value is at/above last map key,
+ // set ceiling speed to the last map key's value
+ speed = it->second;
+ break;
+ }
+ else if (std::next(it, 1) == val_to_speed.rend() &&
+ avgValue <= it->first)
+ {
+ // Value is at/below first map key,
+ // set ceiling speed to the first map key's value
+ speed = it->second;
+ break;
+ }
+ if (avgValue < it->first &&
+ it->first <= prevValue)
+ {
+ // Value decreased & transitioned across a map key,
+ // update ceiling speed to this map key's value
+ // when new value is below map's key and the key
+ // is at/below the previous value
+ speed = it->second;
+ }
+ }
+ }
+ else
+ {// Value is increasing from previous
+ for (auto it = val_to_speed.begin();
+ it != val_to_speed.end();
+ ++it)
+ {
+ if (it == val_to_speed.begin() &&
+ avgValue <= it->first)
+ {
+ // Value is at/below first map key,
+ // set ceiling speed to the first map key's value
+ speed = it->second;
+ break;
+ }
+ else if (std::next(it, 1) == val_to_speed.end() &&
+ avgValue >= it->first)
+ {
+ // Value is at/above last map key,
+ // set ceiling speed to the last map key's value
+ speed = it->second;
+ break;
+ }
+ if (avgValue > it->first &&
+ it->first >= prevValue)
+ {
+ // Value increased & transitioned across a map key,
+ // update ceiling speed to this map key's value
+ // when new value is above map's key and the key
+ // is at/above the previous value
+ speed = it->second;
+ }
+ }
+ }
+ }
+ }
+ zone.setCeiling(speed);
+ };
+}
+
} // namespace action
} // namespace control
} // namespace fan