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