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 */ 16 #include "anyof.hpp" 17 18 #include "fan.hpp" 19 #include "get_power_state.hpp" 20 #include "psensor.hpp" 21 22 #include <phosphor-logging/log.hpp> 23 24 #include <algorithm> 25 26 namespace phosphor 27 { 28 namespace fan 29 { 30 namespace presence 31 { 32 33 using namespace std::chrono_literals; 34 static const auto powerOnDelayTime = 5s; 35 36 AnyOf::AnyOf(const Fan& fan, 37 const std::vector<std::reference_wrapper<PresenceSensor>>& s) : 38 RedundancyPolicy(fan), 39 state(), _powerState(getPowerStateObject()), 40 _powerOnDelayTimer(sdeventplus::Event::get_default(), 41 std::bind(&AnyOf::delayedAfterPowerOn, this)), 42 _powerOn(false) 43 { 44 for (auto& sensor : s) 45 { 46 state.emplace_back(sensor, false, false); 47 } 48 49 _powerState->addCallback( 50 std::get<1>(fan) + "-anyOf", 51 std::bind(&AnyOf::powerStateChanged, this, std::placeholders::_1)); 52 53 // If power is already on, give the fans some time to spin up 54 // before considering power to actually be on. 55 if (_powerState->isPowerOn()) 56 { 57 _powerOnDelayTimer.restartOnce(powerOnDelayTime); 58 } 59 } 60 61 void AnyOf::stateChanged(bool present, PresenceSensor& sensor) 62 { 63 // Find the sensor that changed state. 64 auto sit = 65 std::find_if(state.begin(), state.end(), [&sensor](const auto& s) { 66 return std::get<sensorPos>(s).get() == sensor; 67 }); 68 if (sit != state.end()) 69 { 70 auto origState = 71 std::any_of(state.begin(), state.end(), 72 [](const auto& s) { return std::get<presentPos>(s); }); 73 74 // Update our cache of the sensors state and re-evaluate. 75 std::get<presentPos>(*sit) = present; 76 auto newState = 77 std::any_of(state.begin(), state.end(), 78 [](const auto& s) { return std::get<presentPos>(s); }); 79 setPresence(fan, newState); 80 81 // At least 1 sensor said a fan was present, check if any disagree. 82 if (newState) 83 { 84 if (!origState) 85 { 86 // Fan plug detected, re-enable conflict logging 87 std::for_each(state.begin(), state.end(), [](auto& s) { 88 std::get<conflictPos>(s) = false; 89 }); 90 } 91 92 checkSensorConflicts(); 93 } 94 } 95 } 96 97 void AnyOf::monitor() 98 { 99 // Start all sensors in the anyof redundancy set. 100 101 for (auto& s : state) 102 { 103 auto& sensor = std::get<sensorPos>(s); 104 std::get<presentPos>(s) = sensor.get().start(); 105 } 106 107 auto present = std::any_of(state.begin(), state.end(), [](const auto& s) { 108 return std::get<presentPos>(s); 109 }); 110 setPresence(fan, present); 111 112 // At least one of the contained methods indicated present, 113 // so check that they all agree. 114 if (present) 115 { 116 checkSensorConflicts(); 117 } 118 } 119 120 void AnyOf::checkSensorConflicts() 121 { 122 if (!isPowerOn()) 123 { 124 return; 125 } 126 127 // If at least one, but not all, sensors indicate present, then 128 // tell the not present ones to log a conflict if not already done. 129 if (std::any_of( 130 state.begin(), state.end(), 131 [this](const auto& s) { return std::get<presentPos>(s); }) && 132 !std::all_of(state.begin(), state.end(), 133 [this](const auto& s) { return std::get<presentPos>(s); })) 134 { 135 for (auto& [sensor, present, conflict] : state) 136 { 137 if (!present && !conflict) 138 { 139 sensor.get().logConflict(invNamespace + std::get<1>(fan)); 140 conflict = true; 141 } 142 } 143 } 144 } 145 146 void AnyOf::powerStateChanged(bool powerOn) 147 { 148 if (powerOn) 149 { 150 // Clear the conflict state from last time 151 std::for_each(state.begin(), state.end(), [](auto& state) { 152 std::get<conflictPos>(state) = false; 153 }); 154 155 // Wait to give the fans time to start spinning before 156 // considering power actually on. 157 _powerOnDelayTimer.restartOnce(powerOnDelayTime); 158 } 159 else 160 { 161 _powerOn = false; 162 163 if (_powerOnDelayTimer.isEnabled()) 164 { 165 _powerOnDelayTimer.setEnabled(false); 166 } 167 } 168 } 169 170 void AnyOf::delayedAfterPowerOn() 171 { 172 _powerOn = true; 173 checkSensorConflicts(); 174 } 175 176 } // namespace presence 177 } // namespace fan 178 } // namespace phosphor 179