1dd62e36eSBrad Bishop /**
2dd62e36eSBrad Bishop * Copyright © 2017 IBM Corporation
3dd62e36eSBrad Bishop *
4dd62e36eSBrad Bishop * Licensed under the Apache License, Version 2.0 (the "License");
5dd62e36eSBrad Bishop * you may not use this file except in compliance with the License.
6dd62e36eSBrad Bishop * You may obtain a copy of the License at
7dd62e36eSBrad Bishop *
8dd62e36eSBrad Bishop * http://www.apache.org/licenses/LICENSE-2.0
9dd62e36eSBrad Bishop *
10dd62e36eSBrad Bishop * Unless required by applicable law or agreed to in writing, software
11dd62e36eSBrad Bishop * distributed under the License is distributed on an "AS IS" BASIS,
12dd62e36eSBrad Bishop * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd62e36eSBrad Bishop * See the License for the specific language governing permissions and
14dd62e36eSBrad Bishop * limitations under the License.
15dd62e36eSBrad Bishop */
162d2caa34SMatthew Barth #include "tach.hpp"
172d2caa34SMatthew Barth
18c65d91d6SMatt Spinler #include "logging.hpp"
192d2caa34SMatthew Barth #include "rpolicy.hpp"
202d2caa34SMatthew Barth
21*ebead9a8SAnwaar Hadi #include <phosphor-logging/lg2.hpp>
222d2caa34SMatthew Barth
23fbf4703fSPatrick Williams #include <format>
24dd62e36eSBrad Bishop #include <string>
25dd62e36eSBrad Bishop #include <tuple>
26dd62e36eSBrad Bishop #include <vector>
27dd62e36eSBrad Bishop
28dd62e36eSBrad Bishop namespace phosphor
29dd62e36eSBrad Bishop {
30dd62e36eSBrad Bishop namespace fan
31dd62e36eSBrad Bishop {
32dd62e36eSBrad Bishop namespace presence
33dd62e36eSBrad Bishop {
34dd62e36eSBrad Bishop
35d37c0f85SBrad Bishop using namespace phosphor::logging;
36dd62e36eSBrad Bishop using namespace std::literals::string_literals;
37dd62e36eSBrad Bishop
38dd62e36eSBrad Bishop static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s;
39dd62e36eSBrad Bishop static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s;
40dd62e36eSBrad Bishop static const auto tachProperty = "Value"s;
41dd62e36eSBrad Bishop
Tach(const std::vector<std::string> & sensors)422d2caa34SMatthew Barth Tach::Tach(const std::vector<std::string>& sensors) : currentState(false)
43dd62e36eSBrad Bishop {
44dd62e36eSBrad Bishop // Initialize state.
45dd62e36eSBrad Bishop for (const auto& s : sensors)
46dd62e36eSBrad Bishop {
47dd62e36eSBrad Bishop state.emplace_back(s, nullptr, 0);
48dd62e36eSBrad Bishop }
49dd62e36eSBrad Bishop }
50dd62e36eSBrad Bishop
start()51dd62e36eSBrad Bishop bool Tach::start()
52dd62e36eSBrad Bishop {
53dd62e36eSBrad Bishop for (size_t i = 0; i < state.size(); ++i)
54dd62e36eSBrad Bishop {
55dd62e36eSBrad Bishop auto& s = state[i];
56dd62e36eSBrad Bishop auto tachPath = tachNamespace + std::get<std::string>(s);
57dd62e36eSBrad Bishop
58dd62e36eSBrad Bishop // Register for signal callbacks.
59cb356d48SPatrick Williams std::get<1>(s) = std::make_unique<sdbusplus::bus::match_t>(
60dd62e36eSBrad Bishop util::SDBusPlus::getBus(),
612d2caa34SMatthew Barth sdbusplus::bus::match::rules::propertiesChanged(tachPath,
622d2caa34SMatthew Barth tachIface),
63dd62e36eSBrad Bishop [this, i](auto& msg) { this->propertiesChanged(i, msg); });
64dd62e36eSBrad Bishop
65dd62e36eSBrad Bishop // Get an initial tach speed.
66d37c0f85SBrad Bishop try
67d37c0f85SBrad Bishop {
68ad2cd247SMatthew Barth std::get<double>(s) = util::SDBusPlus::getProperty<double>(
692d2caa34SMatthew Barth tachPath, tachIface, tachProperty);
70dd62e36eSBrad Bishop }
71ddb773b2SPatrick Williams catch (const std::exception&)
72d37c0f85SBrad Bishop {
73d37c0f85SBrad Bishop // Assume not spinning.
74d37c0f85SBrad Bishop
75ad2cd247SMatthew Barth std::get<double>(s) = 0;
76*ebead9a8SAnwaar Hadi lg2::info("Unable to read fan tach sensor {TACPATH}", "TACPATH",
77*ebead9a8SAnwaar Hadi tachPath);
78d37c0f85SBrad Bishop }
79d37c0f85SBrad Bishop }
80dd62e36eSBrad Bishop
81dd62e36eSBrad Bishop // Set the initial state of the sensor.
822d2caa34SMatthew Barth currentState = std::any_of(state.begin(), state.end(), [](const auto& s) {
83ad2cd247SMatthew Barth return std::get<double>(s) != 0;
84dd62e36eSBrad Bishop });
85dd62e36eSBrad Bishop
86dd62e36eSBrad Bishop return currentState;
87dd62e36eSBrad Bishop }
88dd62e36eSBrad Bishop
stop()89dd62e36eSBrad Bishop void Tach::stop()
90dd62e36eSBrad Bishop {
91dd62e36eSBrad Bishop for (auto& s : state)
92dd62e36eSBrad Bishop {
93dd62e36eSBrad Bishop // De-register signal callbacks.
94dd62e36eSBrad Bishop std::get<1>(s) = nullptr;
95dd62e36eSBrad Bishop }
96dd62e36eSBrad Bishop }
97dd62e36eSBrad Bishop
present()98dd62e36eSBrad Bishop bool Tach::present()
99dd62e36eSBrad Bishop {
100dd62e36eSBrad Bishop // Live query the tach readings.
101ad2cd247SMatthew Barth std::vector<double> values;
102dd62e36eSBrad Bishop for (const auto& s : state)
103dd62e36eSBrad Bishop {
104ad2cd247SMatthew Barth values.push_back(util::SDBusPlus::getProperty<double>(
1052d2caa34SMatthew Barth tachNamespace + std::get<std::string>(s), tachIface, tachProperty));
106dd62e36eSBrad Bishop }
107dd62e36eSBrad Bishop
1082d2caa34SMatthew Barth return std::any_of(values.begin(), values.end(),
109dd62e36eSBrad Bishop [](const auto& v) { return v != 0; });
110dd62e36eSBrad Bishop }
111dd62e36eSBrad Bishop
propertiesChanged(size_t sensor,sdbusplus::message_t & msg)112cb356d48SPatrick Williams void Tach::propertiesChanged(size_t sensor, sdbusplus::message_t& msg)
113dd62e36eSBrad Bishop {
114dd62e36eSBrad Bishop std::string iface;
115ad2cd247SMatthew Barth util::Properties<double> properties;
116dd62e36eSBrad Bishop msg.read(iface, properties);
117dd62e36eSBrad Bishop
118dd62e36eSBrad Bishop propertiesChanged(sensor, properties);
119dd62e36eSBrad Bishop }
120dd62e36eSBrad Bishop
propertiesChanged(size_t sensor,const util::Properties<double> & props)1212d2caa34SMatthew Barth void Tach::propertiesChanged(size_t sensor,
122ad2cd247SMatthew Barth const util::Properties<double>& props)
123dd62e36eSBrad Bishop {
124dd62e36eSBrad Bishop // Find the Value property containing the speed.
125dd62e36eSBrad Bishop auto it = props.find(tachProperty);
126dd62e36eSBrad Bishop if (it != props.end())
127dd62e36eSBrad Bishop {
1289f93bd35SMatthew Barth auto& s = state[sensor];
129ad2cd247SMatthew Barth std::get<double>(s) = std::get<double>(it->second);
130dd62e36eSBrad Bishop
1312d2caa34SMatthew Barth auto newState =
132ad2cd247SMatthew Barth std::any_of(state.begin(), state.end(),
133ad2cd247SMatthew Barth [](const auto& s) { return std::get<double>(s) != 0; });
134dd62e36eSBrad Bishop
135dd62e36eSBrad Bishop if (currentState != newState)
136dd62e36eSBrad Bishop {
13711083ecaSBrad Bishop getPolicy().stateChanged(newState, *this);
138dd62e36eSBrad Bishop currentState = newState;
139dd62e36eSBrad Bishop }
140dd62e36eSBrad Bishop }
141dd62e36eSBrad Bishop }
142dd62e36eSBrad Bishop
logConflict(const std::string & fanInventoryPath) const143c65d91d6SMatt Spinler void Tach::logConflict(const std::string& fanInventoryPath) const
144c65d91d6SMatt Spinler {
145fbf4703fSPatrick Williams getLogger().log(std::format(
146c65d91d6SMatt Spinler "Tach sensor presence detect for fan {} said not present but "
147c65d91d6SMatt Spinler "other methods indicated present",
148c65d91d6SMatt Spinler fanInventoryPath));
149c65d91d6SMatt Spinler
150c65d91d6SMatt Spinler // Let the code that monitors fan faults create the event
151c65d91d6SMatt Spinler // logs for stopped rotors.
152c65d91d6SMatt Spinler }
153c65d91d6SMatt Spinler
154dd62e36eSBrad Bishop } // namespace presence
155dd62e36eSBrad Bishop } // namespace fan
156dd62e36eSBrad Bishop } // namespace phosphor
157