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