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