blob: 07a31ebb9b914e34d262fad38bc3e64780fd3f6a [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 <algorithm>
23
Brad Bishop00b52082017-07-25 19:52:22 -040024namespace phosphor
25{
26namespace fan
27{
28namespace presence
29{
Matt Spinlerc65d91d2021-04-21 13:09:49 -050030
31using namespace std::chrono_literals;
32static const auto powerOnDelayTime = 5s;
33
Matthew Barth2d2caa32020-05-26 11:07:24 -050034AnyOf::AnyOf(const Fan& fan,
Matt Spinlerbc4179e2022-10-04 15:15:06 -050035 const std::vector<std::reference_wrapper<PresenceSensor>>& s,
36 std::unique_ptr<EEPROMDevice> e) :
Patrick Williamsdfddd642024-08-16 15:21:51 -040037 RedundancyPolicy(fan, std::move(e)), state(),
38 _powerState(getPowerStateObject()),
Matt Spinlerc65d91d2021-04-21 13:09:49 -050039 _powerOnDelayTimer(sdeventplus::Event::get_default(),
40 std::bind(&AnyOf::delayedAfterPowerOn, this)),
41 _powerOn(false)
Brad Bishop00b52082017-07-25 19:52:22 -040042{
Matthew Barth2d2caa32020-05-26 11:07:24 -050043 for (auto& sensor : s)
Brad Bishop00b52082017-07-25 19:52:22 -040044 {
Matt Spinlerc65d91d2021-04-21 13:09:49 -050045 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);
Brad Bishop00b52082017-07-25 19:52:22 -040057 }
58}
59
60void AnyOf::stateChanged(bool present, PresenceSensor& sensor)
61{
62 // Find the sensor that changed state.
Patrick Williamsdfddd642024-08-16 15:21:51 -040063 auto sit =
64 std::find_if(state.begin(), state.end(), [&sensor](const auto& s) {
65 return std::get<sensorPos>(s).get() == sensor;
66 });
Brad Bishop00b52082017-07-25 19:52:22 -040067 if (sit != state.end())
68 {
Matt Spinlerc65d91d2021-04-21 13:09:49 -050069 auto origState =
70 std::any_of(state.begin(), state.end(),
71 [](const auto& s) { return std::get<presentPos>(s); });
72
Brad Bishop00b52082017-07-25 19:52:22 -040073 // Update our cache of the sensors state and re-evaluate.
Matt Spinlerc65d91d2021-04-21 13:09:49 -050074 std::get<presentPos>(*sit) = present;
Matthew Barth2d2caa32020-05-26 11:07:24 -050075 auto newState =
76 std::any_of(state.begin(), state.end(),
Matt Spinlerc65d91d2021-04-21 13:09:49 -050077 [](const auto& s) { return std::get<presentPos>(s); });
Brad Bishop00b52082017-07-25 19:52:22 -040078 setPresence(fan, newState);
Matt Spinlerc65d91d2021-04-21 13:09:49 -050079
Matt Spinlerbc4179e2022-10-04 15:15:06 -050080 if (eepromDevice && (newState != origState))
81 {
82 if (newState)
83 {
84 eepromDevice->bind();
85 }
86 else
87 {
88 eepromDevice->unbind();
89 }
90 }
91
Matt Spinlerc65d91d2021-04-21 13:09:49 -050092 // 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 }
Brad Bishop00b52082017-07-25 19:52:22 -0400105 }
106}
107
108void AnyOf::monitor()
109{
110 // Start all sensors in the anyof redundancy set.
111
Matthew Barth2d2caa32020-05-26 11:07:24 -0500112 for (auto& s : state)
Brad Bishop00b52082017-07-25 19:52:22 -0400113 {
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500114 auto& sensor = std::get<sensorPos>(s);
115 std::get<presentPos>(s) = sensor.get().start();
Brad Bishop00b52082017-07-25 19:52:22 -0400116 }
117
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500118 auto present = std::any_of(state.begin(), state.end(), [](const auto& s) {
119 return std::get<presentPos>(s);
120 });
Brad Bishop00b52082017-07-25 19:52:22 -0400121 setPresence(fan, present);
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500122
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
131void 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.
Patrick Williamsdfddd642024-08-16 15:21:51 -0400140 if (std::any_of(state.begin(), state.end(),
141 [this](const auto& s) {
142 return std::get<presentPos>(s);
143 }) &&
Matt Spinlerc65d91d2021-04-21 13:09:49 -0500144 !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
158void 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
182void AnyOf::delayedAfterPowerOn()
183{
184 _powerOn = true;
185 checkSensorConflicts();
Brad Bishop00b52082017-07-25 19:52:22 -0400186}
187
188} // namespace presence
189} // namespace fan
190} // namespace phosphor