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 
21ae226194SJay Meyer #include <fmt/format.h>
22ae226194SJay Meyer 
23d37c0f85SBrad Bishop #include <phosphor-logging/log.hpp>
242d2caa34SMatthew Barth 
25dd62e36eSBrad Bishop #include <string>
26dd62e36eSBrad Bishop #include <tuple>
27dd62e36eSBrad Bishop #include <vector>
28dd62e36eSBrad Bishop 
29dd62e36eSBrad Bishop namespace phosphor
30dd62e36eSBrad Bishop {
31dd62e36eSBrad Bishop namespace fan
32dd62e36eSBrad Bishop {
33dd62e36eSBrad Bishop namespace presence
34dd62e36eSBrad Bishop {
35dd62e36eSBrad Bishop 
36d37c0f85SBrad Bishop using namespace phosphor::logging;
37dd62e36eSBrad Bishop using namespace std::literals::string_literals;
38dd62e36eSBrad Bishop 
39dd62e36eSBrad Bishop static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s;
40dd62e36eSBrad Bishop static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s;
41dd62e36eSBrad Bishop static const auto tachProperty = "Value"s;
42dd62e36eSBrad Bishop 
432d2caa34SMatthew Barth Tach::Tach(const std::vector<std::string>& sensors) : currentState(false)
44dd62e36eSBrad Bishop {
45dd62e36eSBrad Bishop     // Initialize state.
46dd62e36eSBrad Bishop     for (const auto& s : sensors)
47dd62e36eSBrad Bishop     {
48dd62e36eSBrad Bishop         state.emplace_back(s, nullptr, 0);
49dd62e36eSBrad Bishop     }
50dd62e36eSBrad Bishop }
51dd62e36eSBrad Bishop 
52dd62e36eSBrad Bishop bool Tach::start()
53dd62e36eSBrad Bishop {
54dd62e36eSBrad Bishop     for (size_t i = 0; i < state.size(); ++i)
55dd62e36eSBrad Bishop     {
56dd62e36eSBrad Bishop         auto& s = state[i];
57dd62e36eSBrad Bishop         auto tachPath = tachNamespace + std::get<std::string>(s);
58dd62e36eSBrad Bishop 
59dd62e36eSBrad Bishop         // Register for signal callbacks.
60*cb356d48SPatrick Williams         std::get<1>(s) = std::make_unique<sdbusplus::bus::match_t>(
61dd62e36eSBrad Bishop             util::SDBusPlus::getBus(),
622d2caa34SMatthew Barth             sdbusplus::bus::match::rules::propertiesChanged(tachPath,
632d2caa34SMatthew Barth                                                             tachIface),
64dd62e36eSBrad Bishop             [this, i](auto& msg) { this->propertiesChanged(i, msg); });
65dd62e36eSBrad Bishop 
66dd62e36eSBrad Bishop         // Get an initial tach speed.
67d37c0f85SBrad Bishop         try
68d37c0f85SBrad Bishop         {
69ad2cd247SMatthew Barth             std::get<double>(s) = util::SDBusPlus::getProperty<double>(
702d2caa34SMatthew Barth                 tachPath, tachIface, tachProperty);
71dd62e36eSBrad Bishop         }
72ddb773b2SPatrick Williams         catch (const std::exception&)
73d37c0f85SBrad Bishop         {
74d37c0f85SBrad Bishop             // Assume not spinning.
75d37c0f85SBrad Bishop 
76ad2cd247SMatthew Barth             std::get<double>(s) = 0;
77ae226194SJay Meyer             log<level::INFO>(
78ae226194SJay Meyer                 fmt::format("Unable to read fan tach sensor {}", tachPath)
79ae226194SJay Meyer                     .c_str());
80d37c0f85SBrad Bishop         }
81d37c0f85SBrad Bishop     }
82dd62e36eSBrad Bishop 
83dd62e36eSBrad Bishop     // Set the initial state of the sensor.
842d2caa34SMatthew Barth     currentState = std::any_of(state.begin(), state.end(), [](const auto& s) {
85ad2cd247SMatthew Barth         return std::get<double>(s) != 0;
86dd62e36eSBrad Bishop     });
87dd62e36eSBrad Bishop 
88dd62e36eSBrad Bishop     return currentState;
89dd62e36eSBrad Bishop }
90dd62e36eSBrad Bishop 
91dd62e36eSBrad Bishop void Tach::stop()
92dd62e36eSBrad Bishop {
93dd62e36eSBrad Bishop     for (auto& s : state)
94dd62e36eSBrad Bishop     {
95dd62e36eSBrad Bishop         // De-register signal callbacks.
96dd62e36eSBrad Bishop         std::get<1>(s) = nullptr;
97dd62e36eSBrad Bishop     }
98dd62e36eSBrad Bishop }
99dd62e36eSBrad Bishop 
100dd62e36eSBrad Bishop bool Tach::present()
101dd62e36eSBrad Bishop {
102dd62e36eSBrad Bishop     // Live query the tach readings.
103ad2cd247SMatthew Barth     std::vector<double> values;
104dd62e36eSBrad Bishop     for (const auto& s : state)
105dd62e36eSBrad Bishop     {
106ad2cd247SMatthew Barth         values.push_back(util::SDBusPlus::getProperty<double>(
1072d2caa34SMatthew Barth             tachNamespace + std::get<std::string>(s), tachIface, tachProperty));
108dd62e36eSBrad Bishop     }
109dd62e36eSBrad Bishop 
1102d2caa34SMatthew Barth     return std::any_of(values.begin(), values.end(),
111dd62e36eSBrad Bishop                        [](const auto& v) { return v != 0; });
112dd62e36eSBrad Bishop }
113dd62e36eSBrad Bishop 
114*cb356d48SPatrick Williams void Tach::propertiesChanged(size_t sensor, sdbusplus::message_t& msg)
115dd62e36eSBrad Bishop {
116dd62e36eSBrad Bishop     std::string iface;
117ad2cd247SMatthew Barth     util::Properties<double> properties;
118dd62e36eSBrad Bishop     msg.read(iface, properties);
119dd62e36eSBrad Bishop 
120dd62e36eSBrad Bishop     propertiesChanged(sensor, properties);
121dd62e36eSBrad Bishop }
122dd62e36eSBrad Bishop 
1232d2caa34SMatthew Barth void Tach::propertiesChanged(size_t sensor,
124ad2cd247SMatthew Barth                              const util::Properties<double>& props)
125dd62e36eSBrad Bishop {
126dd62e36eSBrad Bishop     // Find the Value property containing the speed.
127dd62e36eSBrad Bishop     auto it = props.find(tachProperty);
128dd62e36eSBrad Bishop     if (it != props.end())
129dd62e36eSBrad Bishop     {
1309f93bd35SMatthew Barth         auto& s = state[sensor];
131ad2cd247SMatthew Barth         std::get<double>(s) = std::get<double>(it->second);
132dd62e36eSBrad Bishop 
1332d2caa34SMatthew Barth         auto newState =
134ad2cd247SMatthew Barth             std::any_of(state.begin(), state.end(),
135ad2cd247SMatthew Barth                         [](const auto& s) { return std::get<double>(s) != 0; });
136dd62e36eSBrad Bishop 
137dd62e36eSBrad Bishop         if (currentState != newState)
138dd62e36eSBrad Bishop         {
13911083ecaSBrad Bishop             getPolicy().stateChanged(newState, *this);
140dd62e36eSBrad Bishop             currentState = newState;
141dd62e36eSBrad Bishop         }
142dd62e36eSBrad Bishop     }
143dd62e36eSBrad Bishop }
144dd62e36eSBrad Bishop 
145c65d91d6SMatt Spinler void Tach::logConflict(const std::string& fanInventoryPath) const
146c65d91d6SMatt Spinler {
147c65d91d6SMatt Spinler     getLogger().log(fmt::format(
148c65d91d6SMatt Spinler         "Tach sensor presence detect for fan {} said not present but "
149c65d91d6SMatt Spinler         "other methods indicated present",
150c65d91d6SMatt Spinler         fanInventoryPath));
151c65d91d6SMatt Spinler 
152c65d91d6SMatt Spinler     // Let the code that monitors fan faults create the event
153c65d91d6SMatt Spinler     // logs for stopped rotors.
154c65d91d6SMatt Spinler }
155c65d91d6SMatt Spinler 
156dd62e36eSBrad Bishop } // namespace presence
157dd62e36eSBrad Bishop } // namespace fan
158dd62e36eSBrad Bishop } // namespace phosphor
159