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 signal events 347 * 348 * @return - List of signal events 349 */ 350 inline auto& getSignalEvents() 351 { 352 return _signalEvents; 353 } 354 355 /** 356 * @brief Find the first instance of a signal event 357 * 358 * @param[in] signal - Event signal to find 359 * @param[in] eGroup - Group associated with the signal 360 * @param[in] eActions - List of actions associated with the signal 361 * 362 * @return - Iterator to the stored signal event 363 */ 364 std::vector<SignalEvent>::iterator findSignal( 365 const Signal& signal, 366 const Group& eGroup, 367 const std::vector<Action>& eActions); 368 369 /** 370 * @brief Remove the given signal event 371 * 372 * @param[in] seIter - Iterator pointing to the signal event to remove 373 */ 374 inline void removeSignal(std::vector<SignalEvent>::iterator& seIter) 375 { 376 assert(seIter != std::end(_signalEvents)); 377 std::get<signalEventDataPos>(*seIter).reset(); 378 if (std::get<signalMatchPos>(*seIter) != nullptr) 379 { 380 std::get<signalMatchPos>(*seIter).reset(); 381 } 382 _signalEvents.erase(seIter); 383 } 384 385 /** 386 * @brief Get the list of timer events 387 * 388 * @return - List of timer events 389 */ 390 inline auto& getTimerEvents() 391 { 392 return _timerEvents; 393 } 394 395 /** 396 * @brief Find the first instance of a timer event 397 * 398 * @param[in] eventGroup - Group associated with a timer 399 * @param[in] eventActions - List of actions associated with a timer 400 * 401 * @return - Iterator to the timer event 402 */ 403 std::vector<TimerEvent>::iterator findTimer( 404 const Group& eventGroup, 405 const std::vector<Action>& eventActions); 406 407 /** 408 * @brief Add a timer to the list of timer based events 409 * 410 * @param[in] group - Group associated with a timer 411 * @param[in] actions - List of actions associated with a timer 412 * @param[in] tConf - Configuration for the new timer 413 */ 414 void addTimer(const Group& group, 415 const std::vector<Action>& actions, 416 const TimerConf& tConf); 417 418 /** 419 * @brief Remove the given timer event 420 * 421 * @param[in] teIter - Iterator pointing to the timer event to remove 422 */ 423 inline void removeTimer(std::vector<TimerEvent>::iterator& teIter) 424 { 425 assert(teIter != std::end(_timerEvents)); 426 std::get<timerEventDataPos>(*teIter).reset(); 427 std::get<timerTimerPos>(*teIter).reset(); 428 _timerEvents.erase(teIter); 429 } 430 431 /** 432 * @brief Callback function for event timers that processes the given 433 * actions for a group 434 * 435 * @param[in] eventGroup - Group to process actions on 436 * @param[in] eventActions - List of event actions to run 437 */ 438 void timerExpired(const Group& eventGroup, 439 const std::vector<Action>& eventActions); 440 441 /** 442 * @brief Get the service for a given path and interface from cached 443 * dataset and add a service that's not found 444 * 445 * @param[in] path - Path to get service for 446 * @param[in] intf - Interface to get service for 447 * 448 * @return - The service name 449 */ 450 const std::string& getService(const std::string& path, 451 const std::string& intf); 452 453 /** 454 * @brief Add a set of services for a path and interface 455 * by retrieving all the path subtrees to the given depth 456 * from root for the interface 457 * 458 * @param[in] path - Path to add services for 459 * @param[in] intf - Interface to add services for 460 * @param[in] depth - Depth of tree traversal from root path 461 * 462 * @return - The associated service to the given path and interface 463 * or empty string for no service found 464 */ 465 const std::string& addServices(const std::string& path, 466 const std::string& intf, 467 int32_t depth); 468 469 private: 470 471 /** 472 * The dbus object 473 */ 474 sdbusplus::bus::bus& _bus; 475 476 /** 477 * Full speed for the zone 478 */ 479 const uint64_t _fullSpeed; 480 481 /** 482 * The zone number 483 */ 484 const size_t _zoneNum; 485 486 /** 487 * The default floor speed for the zone 488 */ 489 const uint64_t _defFloorSpeed; 490 491 /** 492 * The default ceiling speed for the zone 493 */ 494 const uint64_t _defCeilingSpeed; 495 496 /** 497 * The floor speed to not go below 498 */ 499 uint64_t _floorSpeed = _defFloorSpeed; 500 501 /** 502 * The ceiling speed to not go above 503 */ 504 uint64_t _ceilingSpeed = _defCeilingSpeed; 505 506 /** 507 * The previous sensor value for calculating the ceiling 508 */ 509 int64_t _ceilingKeyValue = 0; 510 511 /** 512 * Automatic fan control active state 513 */ 514 bool _isActive = true; 515 516 /** 517 * Target speed for this zone 518 */ 519 uint64_t _targetSpeed = _fullSpeed; 520 521 /** 522 * Speed increase delta 523 */ 524 uint64_t _incSpeedDelta = 0; 525 526 /** 527 * Speed decrease delta 528 */ 529 uint64_t _decSpeedDelta = 0; 530 531 /** 532 * Requested speed base 533 */ 534 uint64_t _requestSpeedBase = 0; 535 536 /** 537 * Speed increase delay in seconds 538 */ 539 std::chrono::seconds _incDelay; 540 541 /** 542 * Speed decrease interval in seconds 543 */ 544 std::chrono::seconds _decInterval; 545 546 /** 547 * The increase timer object 548 */ 549 phosphor::fan::util::Timer _incTimer; 550 551 /** 552 * The decrease timer object 553 */ 554 phosphor::fan::util::Timer _decTimer; 555 556 /** 557 * Event loop used on set speed event timers 558 */ 559 sdeventplus::Event _eventLoop; 560 561 /** 562 * The vector of fans in this zone 563 */ 564 std::vector<std::unique_ptr<Fan>> _fans; 565 566 /** 567 * @brief Map of object property values 568 */ 569 std::map<std::string, 570 std::map<std::string, 571 std::map<std::string, 572 PropertyVariantType>>> _properties; 573 574 /** 575 * @brief Map of active fan control allowed by groups 576 */ 577 std::map<const Group, bool> _active; 578 579 /** 580 * @brief Map of floor change allowed by groups 581 */ 582 std::map<const Group, bool> _floorChange; 583 584 /** 585 * @brief Map of groups controlling decreases allowed 586 */ 587 std::map<const Group, bool> _decAllowed; 588 589 /** 590 * @brief Map of group service names 591 */ 592 std::map<const Group, std::vector<Service>> _services; 593 594 /** 595 * @brief Map tree of paths to services of interfaces 596 */ 597 std::map<std::string, 598 std::map<std::string, 599 std::vector<std::string>>> _servTree; 600 601 /** 602 * @brief List of signal event arguments and Dbus matches for callbacks 603 */ 604 std::vector<SignalEvent> _signalEvents; 605 606 /** 607 * @brief List of timers for events 608 */ 609 std::vector<TimerEvent> _timerEvents; 610 611 /** 612 * @brief Get the request speed base if defined, otherwise the 613 * the current target speed is returned 614 * 615 * @return - The request speed base or current target speed 616 */ 617 inline auto getRequestSpeedBase() const 618 { 619 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 620 }; 621 622 /** 623 * @brief Dbus signal change callback handler 624 * 625 * @param[in] msg - Expanded sdbusplus message data 626 * @param[in] eventData - The single event's data 627 */ 628 void handleEvent(sdbusplus::message::message& msg, 629 const EventData* eventData); 630 }; 631 632 } 633 } 634 } 635