| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 1 | /** | 
|  | 2 | * Copyright © 2017 IBM Corporation | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 16 | #include "anyof.hpp" | 
| Matthew Barth | 2d2caa3 | 2020-05-26 11:07:24 -0500 | [diff] [blame] | 17 |  | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 18 | #include "fan.hpp" | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 19 | #include "get_power_state.hpp" | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 20 | #include "psensor.hpp" | 
|  | 21 |  | 
| Matthew Barth | 2d2caa3 | 2020-05-26 11:07:24 -0500 | [diff] [blame] | 22 | #include <phosphor-logging/log.hpp> | 
|  | 23 |  | 
|  | 24 | #include <algorithm> | 
|  | 25 |  | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 26 | namespace phosphor | 
|  | 27 | { | 
|  | 28 | namespace fan | 
|  | 29 | { | 
|  | 30 | namespace presence | 
|  | 31 | { | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 32 |  | 
|  | 33 | using namespace std::chrono_literals; | 
|  | 34 | static const auto powerOnDelayTime = 5s; | 
|  | 35 |  | 
| Matthew Barth | 2d2caa3 | 2020-05-26 11:07:24 -0500 | [diff] [blame] | 36 | AnyOf::AnyOf(const Fan& fan, | 
| Matt Spinler | bc4179e | 2022-10-04 15:15:06 -0500 | [diff] [blame] | 37 | const std::vector<std::reference_wrapper<PresenceSensor>>& s, | 
|  | 38 | std::unique_ptr<EEPROMDevice> e) : | 
| Patrick Williams | dfddd64 | 2024-08-16 15:21:51 -0400 | [diff] [blame^] | 39 | RedundancyPolicy(fan, std::move(e)), state(), | 
|  | 40 | _powerState(getPowerStateObject()), | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 41 | _powerOnDelayTimer(sdeventplus::Event::get_default(), | 
|  | 42 | std::bind(&AnyOf::delayedAfterPowerOn, this)), | 
|  | 43 | _powerOn(false) | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 44 | { | 
| Matthew Barth | 2d2caa3 | 2020-05-26 11:07:24 -0500 | [diff] [blame] | 45 | for (auto& sensor : s) | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 46 | { | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 47 | state.emplace_back(sensor, false, false); | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | _powerState->addCallback( | 
|  | 51 | std::get<1>(fan) + "-anyOf", | 
|  | 52 | std::bind(&AnyOf::powerStateChanged, this, std::placeholders::_1)); | 
|  | 53 |  | 
|  | 54 | // If power is already on, give the fans some time to spin up | 
|  | 55 | // before considering power to actually be on. | 
|  | 56 | if (_powerState->isPowerOn()) | 
|  | 57 | { | 
|  | 58 | _powerOnDelayTimer.restartOnce(powerOnDelayTime); | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 59 | } | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | void AnyOf::stateChanged(bool present, PresenceSensor& sensor) | 
|  | 63 | { | 
|  | 64 | // Find the sensor that changed state. | 
| Patrick Williams | dfddd64 | 2024-08-16 15:21:51 -0400 | [diff] [blame^] | 65 | auto sit = | 
|  | 66 | std::find_if(state.begin(), state.end(), [&sensor](const auto& s) { | 
|  | 67 | return std::get<sensorPos>(s).get() == sensor; | 
|  | 68 | }); | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 69 | if (sit != state.end()) | 
|  | 70 | { | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 71 | auto origState = | 
|  | 72 | std::any_of(state.begin(), state.end(), | 
|  | 73 | [](const auto& s) { return std::get<presentPos>(s); }); | 
|  | 74 |  | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 75 | // Update our cache of the sensors state and re-evaluate. | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 76 | std::get<presentPos>(*sit) = present; | 
| Matthew Barth | 2d2caa3 | 2020-05-26 11:07:24 -0500 | [diff] [blame] | 77 | auto newState = | 
|  | 78 | std::any_of(state.begin(), state.end(), | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 79 | [](const auto& s) { return std::get<presentPos>(s); }); | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 80 | setPresence(fan, newState); | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 81 |  | 
| Matt Spinler | bc4179e | 2022-10-04 15:15:06 -0500 | [diff] [blame] | 82 | if (eepromDevice && (newState != origState)) | 
|  | 83 | { | 
|  | 84 | if (newState) | 
|  | 85 | { | 
|  | 86 | eepromDevice->bind(); | 
|  | 87 | } | 
|  | 88 | else | 
|  | 89 | { | 
|  | 90 | eepromDevice->unbind(); | 
|  | 91 | } | 
|  | 92 | } | 
|  | 93 |  | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 94 | // At least 1 sensor said a fan was present, check if any disagree. | 
|  | 95 | if (newState) | 
|  | 96 | { | 
|  | 97 | if (!origState) | 
|  | 98 | { | 
|  | 99 | // Fan plug detected, re-enable conflict logging | 
|  | 100 | std::for_each(state.begin(), state.end(), [](auto& s) { | 
|  | 101 | std::get<conflictPos>(s) = false; | 
|  | 102 | }); | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | checkSensorConflicts(); | 
|  | 106 | } | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 107 | } | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | void AnyOf::monitor() | 
|  | 111 | { | 
|  | 112 | // Start all sensors in the anyof redundancy set. | 
|  | 113 |  | 
| Matthew Barth | 2d2caa3 | 2020-05-26 11:07:24 -0500 | [diff] [blame] | 114 | for (auto& s : state) | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 115 | { | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 116 | auto& sensor = std::get<sensorPos>(s); | 
|  | 117 | std::get<presentPos>(s) = sensor.get().start(); | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 118 | } | 
|  | 119 |  | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 120 | auto present = std::any_of(state.begin(), state.end(), [](const auto& s) { | 
|  | 121 | return std::get<presentPos>(s); | 
|  | 122 | }); | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 123 | setPresence(fan, present); | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 124 |  | 
|  | 125 | // At least one of the contained methods indicated present, | 
|  | 126 | // so check that they all agree. | 
|  | 127 | if (present) | 
|  | 128 | { | 
|  | 129 | checkSensorConflicts(); | 
|  | 130 | } | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | void AnyOf::checkSensorConflicts() | 
|  | 134 | { | 
|  | 135 | if (!isPowerOn()) | 
|  | 136 | { | 
|  | 137 | return; | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | // If at least one, but not all, sensors indicate present, then | 
|  | 141 | // tell the not present ones to log a conflict if not already done. | 
| Patrick Williams | dfddd64 | 2024-08-16 15:21:51 -0400 | [diff] [blame^] | 142 | if (std::any_of(state.begin(), state.end(), | 
|  | 143 | [this](const auto& s) { | 
|  | 144 | return std::get<presentPos>(s); | 
|  | 145 | }) && | 
| Matt Spinler | c65d91d | 2021-04-21 13:09:49 -0500 | [diff] [blame] | 146 | !std::all_of(state.begin(), state.end(), | 
|  | 147 | [this](const auto& s) { return std::get<presentPos>(s); })) | 
|  | 148 | { | 
|  | 149 | for (auto& [sensor, present, conflict] : state) | 
|  | 150 | { | 
|  | 151 | if (!present && !conflict) | 
|  | 152 | { | 
|  | 153 | sensor.get().logConflict(invNamespace + std::get<1>(fan)); | 
|  | 154 | conflict = true; | 
|  | 155 | } | 
|  | 156 | } | 
|  | 157 | } | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | void AnyOf::powerStateChanged(bool powerOn) | 
|  | 161 | { | 
|  | 162 | if (powerOn) | 
|  | 163 | { | 
|  | 164 | // Clear the conflict state from last time | 
|  | 165 | std::for_each(state.begin(), state.end(), [](auto& state) { | 
|  | 166 | std::get<conflictPos>(state) = false; | 
|  | 167 | }); | 
|  | 168 |  | 
|  | 169 | // Wait to give the fans time to start spinning before | 
|  | 170 | // considering power actually on. | 
|  | 171 | _powerOnDelayTimer.restartOnce(powerOnDelayTime); | 
|  | 172 | } | 
|  | 173 | else | 
|  | 174 | { | 
|  | 175 | _powerOn = false; | 
|  | 176 |  | 
|  | 177 | if (_powerOnDelayTimer.isEnabled()) | 
|  | 178 | { | 
|  | 179 | _powerOnDelayTimer.setEnabled(false); | 
|  | 180 | } | 
|  | 181 | } | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | void AnyOf::delayedAfterPowerOn() | 
|  | 185 | { | 
|  | 186 | _powerOn = true; | 
|  | 187 | checkSensorConflicts(); | 
| Brad Bishop | 00b5208 | 2017-07-25 19:52:22 -0400 | [diff] [blame] | 188 | } | 
|  | 189 |  | 
|  | 190 | } // namespace presence | 
|  | 191 | } // namespace fan | 
|  | 192 | } // namespace phosphor |