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