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 
21d37c0f85SBrad Bishop #include <phosphor-logging/log.hpp>
222d2caa34SMatthew Barth 
23*fbf4703fSPatrick 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;
76ae226194SJay Meyer             log<level::INFO>(
77*fbf4703fSPatrick Williams                 std::format("Unable to read fan tach sensor {}", tachPath)
78ae226194SJay Meyer                     .c_str());
79d37c0f85SBrad Bishop         }
80d37c0f85SBrad Bishop     }
81dd62e36eSBrad Bishop 
82dd62e36eSBrad Bishop     // Set the initial state of the sensor.
832d2caa34SMatthew Barth     currentState = std::any_of(state.begin(), state.end(), [](const auto& s) {
84ad2cd247SMatthew Barth         return std::get<double>(s) != 0;
85dd62e36eSBrad Bishop     });
86dd62e36eSBrad Bishop 
87dd62e36eSBrad Bishop     return currentState;
88dd62e36eSBrad Bishop }
89dd62e36eSBrad Bishop 
stop()90dd62e36eSBrad Bishop void Tach::stop()
91dd62e36eSBrad Bishop {
92dd62e36eSBrad Bishop     for (auto& s : state)
93dd62e36eSBrad Bishop     {
94dd62e36eSBrad Bishop         // De-register signal callbacks.
95dd62e36eSBrad Bishop         std::get<1>(s) = nullptr;
96dd62e36eSBrad Bishop     }
97dd62e36eSBrad Bishop }
98dd62e36eSBrad Bishop 
present()99dd62e36eSBrad Bishop bool Tach::present()
100dd62e36eSBrad Bishop {
101dd62e36eSBrad Bishop     // Live query the tach readings.
102ad2cd247SMatthew Barth     std::vector<double> values;
103dd62e36eSBrad Bishop     for (const auto& s : state)
104dd62e36eSBrad Bishop     {
105ad2cd247SMatthew Barth         values.push_back(util::SDBusPlus::getProperty<double>(
1062d2caa34SMatthew Barth             tachNamespace + std::get<std::string>(s), tachIface, tachProperty));
107dd62e36eSBrad Bishop     }
108dd62e36eSBrad Bishop 
1092d2caa34SMatthew Barth     return std::any_of(values.begin(), values.end(),
110dd62e36eSBrad Bishop                        [](const auto& v) { return v != 0; });
111dd62e36eSBrad Bishop }
112dd62e36eSBrad Bishop 
propertiesChanged(size_t sensor,sdbusplus::message_t & msg)113cb356d48SPatrick Williams void Tach::propertiesChanged(size_t sensor, sdbusplus::message_t& msg)
114dd62e36eSBrad Bishop {
115dd62e36eSBrad Bishop     std::string iface;
116ad2cd247SMatthew Barth     util::Properties<double> properties;
117dd62e36eSBrad Bishop     msg.read(iface, properties);
118dd62e36eSBrad Bishop 
119dd62e36eSBrad Bishop     propertiesChanged(sensor, properties);
120dd62e36eSBrad Bishop }
121dd62e36eSBrad Bishop 
propertiesChanged(size_t sensor,const util::Properties<double> & props)1222d2caa34SMatthew Barth void Tach::propertiesChanged(size_t sensor,
123ad2cd247SMatthew Barth                              const util::Properties<double>& props)
124dd62e36eSBrad Bishop {
125dd62e36eSBrad Bishop     // Find the Value property containing the speed.
126dd62e36eSBrad Bishop     auto it = props.find(tachProperty);
127dd62e36eSBrad Bishop     if (it != props.end())
128dd62e36eSBrad Bishop     {
1299f93bd35SMatthew Barth         auto& s = state[sensor];
130ad2cd247SMatthew Barth         std::get<double>(s) = std::get<double>(it->second);
131dd62e36eSBrad Bishop 
1322d2caa34SMatthew Barth         auto newState =
133ad2cd247SMatthew Barth             std::any_of(state.begin(), state.end(),
134ad2cd247SMatthew Barth                         [](const auto& s) { return std::get<double>(s) != 0; });
135dd62e36eSBrad Bishop 
136dd62e36eSBrad Bishop         if (currentState != newState)
137dd62e36eSBrad Bishop         {
13811083ecaSBrad Bishop             getPolicy().stateChanged(newState, *this);
139dd62e36eSBrad Bishop             currentState = newState;
140dd62e36eSBrad Bishop         }
141dd62e36eSBrad Bishop     }
142dd62e36eSBrad Bishop }
143dd62e36eSBrad Bishop 
logConflict(const std::string & fanInventoryPath) const144c65d91d6SMatt Spinler void Tach::logConflict(const std::string& fanInventoryPath) const
145c65d91d6SMatt Spinler {
146*fbf4703fSPatrick Williams     getLogger().log(std::format(
147c65d91d6SMatt Spinler         "Tach sensor presence detect for fan {} said not present but "
148c65d91d6SMatt Spinler         "other methods indicated present",
149c65d91d6SMatt Spinler         fanInventoryPath));
150c65d91d6SMatt Spinler 
151c65d91d6SMatt Spinler     // Let the code that monitors fan faults create the event
152c65d91d6SMatt Spinler     // logs for stopped rotors.
153c65d91d6SMatt Spinler }
154c65d91d6SMatt Spinler 
155dd62e36eSBrad Bishop } // namespace presence
156dd62e36eSBrad Bishop } // namespace fan
157dd62e36eSBrad Bishop } // namespace phosphor
158