blob: 635e6a647862622f0ce1618b83108a3d376b2830 [file] [log] [blame]
Brad Bishop00b52082017-07-25 19:52:22 -04001/**
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 Bishop00b52082017-07-25 19:52:22 -040016#include "anyof.hpp"
Matthew Barth2d2caa32020-05-26 11:07:24 -050017
Brad Bishop00b52082017-07-25 19:52:22 -040018#include "fan.hpp"
Matt Spinlerc65d91d2021-04-21 13:09:49 -050019#include "get_power_state.hpp"
Brad Bishop00b52082017-07-25 19:52:22 -040020#include "psensor.hpp"
21
Matthew Barth2d2caa32020-05-26 11:07:24 -050022#include <phosphor-logging/log.hpp>
23
24#include <algorithm>
25
Brad Bishop00b52082017-07-25 19:52:22 -040026namespace phosphor
27{
28namespace fan
29{
30namespace presence
31{
Matt Spinlerc65d91d2021-04-21 13:09:49 -050032
33using namespace std::chrono_literals;
34static const auto powerOnDelayTime = 5s;
35
Matthew Barth2d2caa32020-05-26 11:07:24 -050036AnyOf::AnyOf(const Fan& fan,
Matt Spinlerbc4179e2022-10-04 15:15:06 -050037 const std::vector<std::reference_wrapper<PresenceSensor>>& s,
38 std::unique_ptr<EEPROMDevice> e) :
Patrick Williamsdfddd642024-08-16 15:21:51 -040039 RedundancyPolicy(fan, std::move(e)), state(),
40 _powerState(getPowerStateObject()),
Matt Spinlerc65d91d2021-04-21 13:09:49 -050041 _powerOnDelayTimer(sdeventplus::Event::get_default(),
42 std::bind(&AnyOf::delayedAfterPowerOn, this)),
43 _powerOn(false)
Brad Bishop00b52082017-07-25 19:52:22 -040044{
Matthew Barth2d2caa32020-05-26 11:07:24 -050045 for (auto& sensor : s)
Brad Bishop00b52082017-07-25 19:52:22 -040046 {
Matt Spinlerc65d91d2021-04-21 13:09:49 -050047 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 Bishop00b52082017-07-25 19:52:22 -040059 }
60}
61
62void AnyOf::stateChanged(bool present, PresenceSensor& sensor)
63{
64 // Find the sensor that changed state.
Patrick Williamsdfddd642024-08-16 15:21:51 -040065 auto sit =
66 std::find_if(state.begin(), state.end(), [&sensor](const auto& s) {
67 return std::get<sensorPos>(s).get() == sensor;
68 });
Brad Bishop00b52082017-07-25 19:52:22 -040069 if (sit != state.end())
70 {
Matt Spinlerc65d91d2021-04-21 13:09:49 -050071 auto origState =
72 std::any_of(state.begin(), state.end(),
73 [](const auto& s) { return std::get<presentPos>(s); });
74
Brad Bishop00b52082017-07-25 19:52:22 -040075 // Update our cache of the sensors state and re-evaluate.
Matt Spinlerc65d91d2021-04-21 13:09:49 -050076 std::get<presentPos>(*sit) = present;
Matthew Barth2d2caa32020-05-26 11:07:24 -050077 auto newState =
78 std::any_of(state.begin(), state.end(),
Matt Spinlerc65d91d2021-04-21 13:09:49 -050079 [](const auto& s) { return std::get<presentPos>(s); });
Brad Bishop00b52082017-07-25 19:52:22 -040080 setPresence(fan, newState);
Matt Spinlerc65d91d2021-04-21 13:09:49 -050081
Matt Spinlerbc4179e2022-10-04 15:15:06 -050082 if (eepromDevice && (newState != origState))
83 {
84 if (newState)
85 {
86 eepromDevice->bind();
87 }
88 else
89 {
90 eepromDevice->unbind();
91 }
92 }
93
Matt Spinlerc65d91d2021-04-21 13:09:49 -050094 // 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 Bishop00b52082017-07-25 19:52:22 -0400107 }
108}
109
110void AnyOf::monitor()
111{
112 // Start all sensors in the anyof redundancy set.
113
Matthew Barth2d2caa32020-05-26 11:07:24 -0500114 for (auto& s : state)
Brad Bishop00b52082017-07-25 19:52:22 -0400115 {
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500116 auto& sensor = std::get<sensorPos>(s);
117 std::get<presentPos>(s) = sensor.get().start();
Brad Bishop00b52082017-07-25 19:52:22 -0400118 }
119
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500120 auto present = std::any_of(state.begin(), state.end(), [](const auto& s) {
121 return std::get<presentPos>(s);
122 });
Brad Bishop00b52082017-07-25 19:52:22 -0400123 setPresence(fan, present);
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500124
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
133void 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 Williamsdfddd642024-08-16 15:21:51 -0400142 if (std::any_of(state.begin(), state.end(),
143 [this](const auto& s) {
144 return std::get<presentPos>(s);
145 }) &&
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500146 !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
160void 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
184void AnyOf::delayedAfterPowerOn()
185{
186 _powerOn = true;
187 checkSensorConflicts();
Brad Bishop00b52082017-07-25 19:52:22 -0400188}
189
190} // namespace presence
191} // namespace fan
192} // namespace phosphor