1 #pragma once 2 #include <chrono> 3 #include <vector> 4 #include <cassert> 5 #include <algorithm> 6 #include <sdbusplus/bus.hpp> 7 #include <sdeventplus/event.hpp> 8 #include "fan.hpp" 9 #include "types.hpp" 10 #include "timer.hpp" 11 12 namespace phosphor 13 { 14 namespace fan 15 { 16 namespace control 17 { 18 19 /** 20 * The mode fan control will run in: 21 * - init - only do the initialization steps 22 * - control - run normal control algorithms 23 */ 24 enum class Mode 25 { 26 init, 27 control 28 }; 29 30 /** 31 * @class Represents a fan control zone, which is a group of fans 32 * that behave the same. 33 */ 34 class Zone 35 { 36 public: 37 38 Zone() = delete; 39 Zone(const Zone&) = delete; 40 Zone(Zone&&) = delete; 41 Zone& operator=(const Zone&) = delete; 42 Zone& operator=(Zone&&) = delete; 43 ~Zone() = default; 44 45 /** 46 * Constructor 47 * Creates the appropriate fan objects based on 48 * the zone definition data passed in. 49 * 50 * @param[in] mode - mode of fan control 51 * @param[in] bus - the dbus object 52 * @param[in] event - Event loop reference 53 * @param[in] def - the fan zone definition data 54 */ 55 Zone(Mode mode, 56 sdbusplus::bus::bus& bus, 57 const sdeventplus::Event& event, 58 const ZoneDefinition& def); 59 60 /** 61 * Sets all fans in the zone to the speed 62 * passed in when the zone is active 63 * 64 * @param[in] speed - the fan speed 65 */ 66 void setSpeed(uint64_t speed); 67 68 /** 69 * Sets the zone to full speed regardless of zone's active state 70 */ 71 void setFullSpeed(); 72 73 /** 74 * @brief Sets the automatic fan control allowed active state 75 * 76 * @param[in] group - A group that affects the active state 77 * @param[in] isActiveAllow - Active state according to group 78 */ 79 void setActiveAllow(const Group* group, bool isActiveAllow); 80 81 /** 82 * @brief Sets the floor change allowed state 83 * 84 * @param[in] group - A group that affects floor changes 85 * @param[in] isAllow - Allow state according to group 86 */ 87 inline void setFloorChangeAllow(const Group* group, bool isAllow) 88 { 89 _floorChange[*(group)] = isAllow; 90 } 91 92 /** 93 * @brief Sets the decrease allowed state of a group 94 * 95 * @param[in] group - A group that affects speed decreases 96 * @param[in] isAllow - Allow state according to group 97 */ 98 inline void setDecreaseAllow(const Group* group, bool isAllow) 99 { 100 _decAllowed[*(group)] = isAllow; 101 } 102 103 /** 104 * @brief Sets a given object's property value 105 * 106 * @param[in] object - Name of the object containing the property 107 * @param[in] interface - Interface name containing the property 108 * @param[in] property - Property name 109 * @param[in] value - Property value 110 */ 111 template <typename T> 112 void setPropertyValue(const char* object, 113 const char* interface, 114 const char* property, 115 T value) 116 { 117 _properties[object][interface][property] = value; 118 }; 119 120 /** 121 * @brief Get the value of an object's property 122 * 123 * @param[in] object - Name of the object containing the property 124 * @param[in] interface - Interface name containing the property 125 * @param[in] property - Property name 126 * 127 * @return - The property value 128 */ 129 template <typename T> 130 inline auto getPropertyValue(const std::string& object, 131 const std::string& interface, 132 const std::string& property) 133 { 134 return sdbusplus::message::variant_ns::get<T>( 135 _properties.at(object).at(interface).at(property)); 136 }; 137 138 /** 139 * @brief Get the object's property variant 140 * 141 * @param[in] object - Name of the object containing the property 142 * @param[in] interface - Interface name containing the property 143 * @param[in] property - Property name 144 * 145 * @return - The property variant 146 */ 147 inline auto getPropValueVariant(const std::string& object, 148 const std::string& interface, 149 const std::string& property) 150 { 151 return _properties.at(object).at(interface).at(property); 152 }; 153 154 /** 155 * @brief Remove an object's interface 156 * 157 * @param[in] object - Name of the object with the interface 158 * @param[in] interface - Interface name to remove 159 */ 160 inline void removeObjectInterface(const char* object, 161 const char* interface) 162 { 163 auto it = _properties.find(object); 164 if (it != std::end(_properties)) 165 { 166 _properties[object].erase(interface); 167 } 168 } 169 170 /** 171 * @brief Remove a service associated to a group 172 * 173 * @param[in] group - Group associated with service 174 * @param[in] name - Service name to remove 175 */ 176 void removeService(const Group* group, 177 const std::string& name); 178 179 /** 180 * @brief Set or update a service name owner in use 181 * 182 * @param[in] group - Group associated with service 183 * @param[in] name - Service name 184 * @param[in] hasOwner - Whether the service is owned or not 185 */ 186 void setServiceOwner(const Group* group, 187 const std::string& name, 188 const bool hasOwner); 189 190 /** 191 * @brief Set or update all services for a group 192 * 193 * @param[in] group - Group to get service names for 194 */ 195 void setServices(const Group* group); 196 197 /** 198 * @brief Get the group's list of service names 199 * 200 * @param[in] group - Group to get service names for 201 * 202 * @return - The list of service names 203 */ 204 inline auto getGroupServices(const Group* group) 205 { 206 return _services.at(*group); 207 } 208 209 /** 210 * @brief Initialize a set speed event properties and actions 211 * 212 * @param[in] event - Set speed event 213 */ 214 void initEvent(const SetSpeedEvent& event); 215 216 /** 217 * @brief Removes all the set speed event properties and actions 218 * 219 * @param[in] event - Set speed event 220 */ 221 void removeEvent(const SetSpeedEvent& event); 222 223 /** 224 * @brief Get the default floor speed 225 * 226 * @return - The defined default floor speed 227 */ 228 inline auto getDefFloor() 229 { 230 return _defFloorSpeed; 231 }; 232 233 /** 234 * @brief Get the ceiling speed 235 * 236 * @return - The current ceiling speed 237 */ 238 inline auto& getCeiling() const 239 { 240 return _ceilingSpeed; 241 }; 242 243 /** 244 * @brief Set the ceiling speed to the given speed 245 * 246 * @param[in] speed - Speed to set the ceiling to 247 */ 248 inline void setCeiling(uint64_t speed) 249 { 250 _ceilingSpeed = speed; 251 }; 252 253 /** 254 * @brief Swaps the ceiling key value with what's given and 255 * returns the value that was swapped. 256 * 257 * @param[in] keyValue - New ceiling key value 258 * 259 * @return - Ceiling key value prior to swapping 260 */ 261 inline auto swapCeilingKeyValue(int64_t keyValue) 262 { 263 std::swap(_ceilingKeyValue, keyValue); 264 return keyValue; 265 }; 266 267 /** 268 * @brief Get the increase speed delta 269 * 270 * @return - The current increase speed delta 271 */ 272 inline auto& getIncSpeedDelta() const 273 { 274 return _incSpeedDelta; 275 }; 276 277 /** 278 * @brief Get the decrease speed delta 279 * 280 * @return - The current decrease speed delta 281 */ 282 inline auto& getDecSpeedDelta() const 283 { 284 return _decSpeedDelta; 285 }; 286 287 /** 288 * @brief Set the floor speed to the given speed and increase target 289 * speed to the floor when target is below floor where floor changes 290 * are allowed. 291 * 292 * @param[in] speed - Speed to set the floor to 293 */ 294 void setFloor(uint64_t speed); 295 296 /** 297 * @brief Set the requested speed base to be used as the speed to 298 * base a new requested speed target from 299 * 300 * @param[in] speedBase - Base speed value to use 301 */ 302 inline void setRequestSpeedBase(uint64_t speedBase) 303 { 304 _requestSpeedBase = speedBase; 305 }; 306 307 /** 308 * @brief Calculate the requested target speed from the given delta 309 * and increase the fan speeds, not going above the ceiling. 310 * 311 * @param[in] targetDelta - The delta to increase the target speed by 312 */ 313 void requestSpeedIncrease(uint64_t targetDelta); 314 315 /** 316 * @brief Calculate the requested target speed from the given delta 317 * and increase the fan speeds, not going above the ceiling. 318 * 319 * @param[in] targetDelta - The delta to increase the target speed by 320 */ 321 void requestSpeedDecrease(uint64_t targetDelta); 322 323 /** 324 * @brief Callback function for the increase timer that delays 325 * processing of requested speed increases while fans are increasing 326 */ 327 void incTimerExpired(); 328 329 /** 330 * @brief Callback function for the decrease timer that processes any 331 * requested speed decreases if allowed 332 */ 333 void decTimerExpired(); 334 335 /** 336 * @brief Get the event loop used with this zone's timers 337 * 338 * @return - The event loop for timers 339 */ 340 inline auto& getEventLoop() 341 { 342 return _eventLoop; 343 } 344 345 /** 346 * @brief Get the list of timer events 347 * 348 * @return - List of timer events 349 */ 350 inline auto& getTimerEvents() 351 { 352 return _timerEvents; 353 } 354 355 /** 356 * @brief Find the first instance of a timer event 357 * 358 * @param[in] eventGroup - Group associated with a timer 359 * @param[in] eventActions - List of actions associated with a timer 360 * 361 * @return - Iterator to the timer event 362 */ 363 std::vector<TimerEvent>::iterator findTimer( 364 const Group& eventGroup, 365 const std::vector<Action>& eventActions); 366 367 /** 368 * @brief Add a timer to the list of timer based events 369 * 370 * @param[in] data - Event data for timer 371 * @param[in] timer - Timer to be added 372 */ 373 inline void addTimer( 374 std::unique_ptr<EventData>&& data, 375 std::unique_ptr<phosphor::fan::util::Timer>&& timer) 376 { 377 _timerEvents.emplace_back(std::move(data), std::move(timer)); 378 }; 379 380 /** 381 * @brief Remove the given timer event 382 * 383 * @param[in] teIter - Iterator pointing to the timer event to remove 384 */ 385 inline void removeTimer(std::vector<TimerEvent>::iterator& teIter) 386 { 387 assert(teIter != std::end(_timerEvents)); 388 std::get<timerEventDataPos>(*teIter).reset(); 389 std::get<timerTimerPos>(*teIter).reset(); 390 _timerEvents.erase(teIter); 391 } 392 393 /** 394 * @brief Callback function for event timers that processes the given 395 * actions for a group 396 * 397 * @param[in] eventGroup - Group to process actions on 398 * @param[in] eventActions - List of event actions to run 399 */ 400 void timerExpired(Group eventGroup, std::vector<Action> eventActions); 401 402 /** 403 * @brief Get the service for a given path and interface from cached 404 * dataset and add a service that's not found 405 * 406 * @param[in] path - Path to get service for 407 * @param[in] intf - Interface to get service for 408 * 409 * @return - The service name 410 */ 411 const std::string& getService(const std::string& path, 412 const std::string& intf); 413 414 /** 415 * @brief Add a set of services for a path and interface 416 * by retrieving all the path subtrees to the given depth 417 * from root for the interface 418 * 419 * @param[in] path - Path to add services for 420 * @param[in] intf - Interface to add services for 421 * @param[in] depth - Depth of tree traversal from root path 422 * 423 * @return - The associated service to the given path and interface 424 * or empty string for no service found 425 */ 426 const std::string& addServices(const std::string& path, 427 const std::string& intf, 428 int32_t depth); 429 430 private: 431 432 /** 433 * The dbus object 434 */ 435 sdbusplus::bus::bus& _bus; 436 437 /** 438 * Full speed for the zone 439 */ 440 const uint64_t _fullSpeed; 441 442 /** 443 * The zone number 444 */ 445 const size_t _zoneNum; 446 447 /** 448 * The default floor speed for the zone 449 */ 450 const uint64_t _defFloorSpeed; 451 452 /** 453 * The default ceiling speed for the zone 454 */ 455 const uint64_t _defCeilingSpeed; 456 457 /** 458 * The floor speed to not go below 459 */ 460 uint64_t _floorSpeed = _defFloorSpeed; 461 462 /** 463 * The ceiling speed to not go above 464 */ 465 uint64_t _ceilingSpeed = _defCeilingSpeed; 466 467 /** 468 * The previous sensor value for calculating the ceiling 469 */ 470 int64_t _ceilingKeyValue = 0; 471 472 /** 473 * Automatic fan control active state 474 */ 475 bool _isActive = true; 476 477 /** 478 * Target speed for this zone 479 */ 480 uint64_t _targetSpeed = _fullSpeed; 481 482 /** 483 * Speed increase delta 484 */ 485 uint64_t _incSpeedDelta = 0; 486 487 /** 488 * Speed decrease delta 489 */ 490 uint64_t _decSpeedDelta = 0; 491 492 /** 493 * Requested speed base 494 */ 495 uint64_t _requestSpeedBase = 0; 496 497 /** 498 * Speed increase delay in seconds 499 */ 500 std::chrono::seconds _incDelay; 501 502 /** 503 * Speed decrease interval in seconds 504 */ 505 std::chrono::seconds _decInterval; 506 507 /** 508 * The increase timer object 509 */ 510 phosphor::fan::util::Timer _incTimer; 511 512 /** 513 * The decrease timer object 514 */ 515 phosphor::fan::util::Timer _decTimer; 516 517 /** 518 * Event loop used on set speed event timers 519 */ 520 sdeventplus::Event _eventLoop; 521 522 /** 523 * The vector of fans in this zone 524 */ 525 std::vector<std::unique_ptr<Fan>> _fans; 526 527 /** 528 * @brief Map of object property values 529 */ 530 std::map<std::string, 531 std::map<std::string, 532 std::map<std::string, 533 PropertyVariantType>>> _properties; 534 535 /** 536 * @brief Map of active fan control allowed by groups 537 */ 538 std::map<const Group, bool> _active; 539 540 /** 541 * @brief Map of floor change allowed by groups 542 */ 543 std::map<const Group, bool> _floorChange; 544 545 /** 546 * @brief Map of groups controlling decreases allowed 547 */ 548 std::map<const Group, bool> _decAllowed; 549 550 /** 551 * @brief Map of group service names 552 */ 553 std::map<const Group, std::vector<Service>> _services; 554 555 /** 556 * @brief Map tree of paths to services of interfaces 557 */ 558 std::map<std::string, 559 std::map<std::string, 560 std::vector<std::string>>> _servTree; 561 562 /** 563 * @brief List of signal event arguments and Dbus matches for callbacks 564 */ 565 std::vector<SignalEvent> _signalEvents; 566 567 /** 568 * @brief List of timers for events 569 */ 570 std::vector<TimerEvent> _timerEvents; 571 572 /** 573 * @brief Get the request speed base if defined, otherwise the 574 * the current target speed is returned 575 * 576 * @return - The request speed base or current target speed 577 */ 578 inline auto getRequestSpeedBase() const 579 { 580 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 581 }; 582 583 /** 584 * @brief Dbus signal change callback handler 585 * 586 * @param[in] msg - Expanded sdbusplus message data 587 * @param[in] eventData - The single event's data 588 */ 589 void handleEvent(sdbusplus::message::message& msg, 590 const EventData* eventData); 591 }; 592 593 } 594 } 595 } 596