blob: 8ecd30cce70519902421d0af9f15553f71390ddf [file] [log] [blame]
#include "actions.hpp"
namespace phosphor
{
namespace fan
{
namespace control
{
namespace action
{
using namespace phosphor::fan;
Action call_actions_based_on_timer(Timer&& tConf, std::vector<Action>&& actions)
{
return [tConf = std::move(tConf),
actions = std::move(actions)](control::Zone& zone,
const Group& group)
{
try
{
// Find any services that do not have an owner
auto services = zone.getGroupServices(&group);
auto setTimer = std::any_of(
services.begin(),
services.end(),
[](const auto& s)
{
return !std::get<hasOwnerPos>(s);
});
if (setTimer &&
zone.findTimer(group, actions) ==
std::end(zone.getTimerEvents()))
{
// Associate event data with timer
std::unique_ptr<EventData> eventData =
std::make_unique<EventData>(
EventData
{
group,
"",
nullptr,
actions
}
);
// Create/start timer and associate event data with it
std::unique_ptr<util::Timer> timer =
std::make_unique<util::Timer>(
zone.getEventPtr(),
[&zone,
actions = &actions,
group = &group]()
{
zone.timerExpired(*group, *actions);
});
if (!timer->running())
{
timer->start(std::get<intervalPos>(tConf),
std::get<typePos>(tConf));
}
zone.addTimer(std::move(eventData), std::move(timer));
}
else
{
// Stop and remove any timers for this group
auto timer = zone.findTimer(group, actions);
if (timer != std::end(zone.getTimerEvents()))
{
if (std::get<timerTimerPos>(*timer)->running())
{
std::get<timerTimerPos>(*timer)->stop();
}
zone.removeTimer(timer);
}
}
}
catch (const std::out_of_range& oore)
{
// Group not found, no timers set
}
};
}
void default_floor_on_missing_owner(Zone& zone, const Group& group)
{
// Set/update the services of the group
zone.setServices(&group);
auto services = zone.getGroupServices(&group);
auto defFloor = std::any_of(
services.begin(),
services.end(),
[](const auto& s)
{
return !std::get<hasOwnerPos>(s);
});
if (defFloor)
{
zone.setFloor(zone.getDefFloor());
}
// Update fan control floor change allowed
zone.setFloorChangeAllow(&group, !defFloor);
}
Action set_speed_on_missing_owner(uint64_t speed)
{
return [speed](control::Zone& zone, const Group& group)
{
// Set/update the services of the group
zone.setServices(&group);
auto services = zone.getGroupServices(&group);
auto missingOwner = std::any_of(
services.begin(),
services.end(),
[](const auto& s)
{
return !std::get<hasOwnerPos>(s);
});
if (missingOwner)
{
zone.setSpeed(speed);
}
// Update group's fan control active allowed based on action results
zone.setActiveAllow(&group, !missingOwner);
};
}
void set_request_speed_base_with_max(control::Zone& zone,
const Group& group)
{
int64_t base = 0;
std::for_each(
group.begin(),
group.end(),
[&zone, &base](auto const& entry)
{
try
{
auto value = zone.template getPropertyValue<int64_t>(
entry.first,
std::get<intfPos>(entry.second),
std::get<propPos>(entry.second));
base = std::max(base, value);
}
catch (const std::out_of_range& oore)
{
// Property value not found, base request speed unchanged
}
});
// A request speed base of 0 defaults to the current target speed
zone.setRequestSpeedBase(base);
}
Action set_floor_from_average_sensor_value(
std::map<int64_t, uint64_t>&& val_to_speed)
{
return [val_to_speed = std::move(val_to_speed)](control::Zone& zone,
const Group& group)
{
auto speed = zone.getDefFloor();
if (group.size() != 0)
{
auto count = 0;
auto sumValue = std::accumulate(
group.begin(),
group.end(),
0,
[&zone, &count](int64_t sum, auto const& entry)
{
try
{
return sum +
zone.template getPropertyValue<int64_t>(
entry.first,
std::get<intfPos>(entry.second),
std::get<propPos>(entry.second));
}
catch (const std::out_of_range& oore)
{
count++;
return sum;
}
});
if ((group.size() - count) > 0)
{
auto groupSize = static_cast<int64_t>(group.size());
auto avgValue = sumValue / (groupSize - count);
auto it = std::find_if(
val_to_speed.begin(),
val_to_speed.end(),
[&avgValue](auto const& entry)
{
return avgValue < entry.first;
}
);
if (it != std::end(val_to_speed))
{
speed = (*it).second;
}
}
}
zone.setFloor(speed);
};
}
Action set_ceiling_from_average_sensor_value(
std::map<int64_t, uint64_t>&& val_to_speed)
{
return [val_to_speed = std::move(val_to_speed)](Zone& zone,
const Group& group)
{
auto speed = zone.getCeiling();
if (group.size() != 0)
{
auto count = 0;
auto sumValue = std::accumulate(
group.begin(),
group.end(),
0,
[&zone, &count](int64_t sum, auto const& entry)
{
try
{
return sum +
zone.template getPropertyValue<int64_t>(
entry.first,
std::get<intfPos>(entry.second),
std::get<propPos>(entry.second));
}
catch (const std::out_of_range& oore)
{
count++;
return sum;
}
});
if ((group.size() - count) > 0)
{
auto groupSize = static_cast<int64_t>(group.size());
auto avgValue = sumValue / (groupSize - count);
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
} // namespace phosphor