| /** |
| * Copyright © 2017 IBM Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "tach.hpp" |
| |
| #include "logging.hpp" |
| #include "rpolicy.hpp" |
| |
| #include <phosphor-logging/log.hpp> |
| |
| #include <format> |
| #include <string> |
| #include <tuple> |
| #include <vector> |
| |
| namespace phosphor |
| { |
| namespace fan |
| { |
| namespace presence |
| { |
| |
| using namespace phosphor::logging; |
| using namespace std::literals::string_literals; |
| |
| static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s; |
| static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s; |
| static const auto tachProperty = "Value"s; |
| |
| Tach::Tach(const std::vector<std::string>& sensors) : currentState(false) |
| { |
| // Initialize state. |
| for (const auto& s : sensors) |
| { |
| state.emplace_back(s, nullptr, 0); |
| } |
| } |
| |
| bool Tach::start() |
| { |
| for (size_t i = 0; i < state.size(); ++i) |
| { |
| auto& s = state[i]; |
| auto tachPath = tachNamespace + std::get<std::string>(s); |
| |
| // Register for signal callbacks. |
| std::get<1>(s) = std::make_unique<sdbusplus::bus::match_t>( |
| util::SDBusPlus::getBus(), |
| sdbusplus::bus::match::rules::propertiesChanged(tachPath, |
| tachIface), |
| [this, i](auto& msg) { this->propertiesChanged(i, msg); }); |
| |
| // Get an initial tach speed. |
| try |
| { |
| std::get<double>(s) = util::SDBusPlus::getProperty<double>( |
| tachPath, tachIface, tachProperty); |
| } |
| catch (const std::exception&) |
| { |
| // Assume not spinning. |
| |
| std::get<double>(s) = 0; |
| log<level::INFO>( |
| std::format("Unable to read fan tach sensor {}", tachPath) |
| .c_str()); |
| } |
| } |
| |
| // Set the initial state of the sensor. |
| currentState = std::any_of(state.begin(), state.end(), [](const auto& s) { |
| return std::get<double>(s) != 0; |
| }); |
| |
| return currentState; |
| } |
| |
| void Tach::stop() |
| { |
| for (auto& s : state) |
| { |
| // De-register signal callbacks. |
| std::get<1>(s) = nullptr; |
| } |
| } |
| |
| bool Tach::present() |
| { |
| // Live query the tach readings. |
| std::vector<double> values; |
| for (const auto& s : state) |
| { |
| values.push_back(util::SDBusPlus::getProperty<double>( |
| tachNamespace + std::get<std::string>(s), tachIface, tachProperty)); |
| } |
| |
| return std::any_of(values.begin(), values.end(), |
| [](const auto& v) { return v != 0; }); |
| } |
| |
| void Tach::propertiesChanged(size_t sensor, sdbusplus::message_t& msg) |
| { |
| std::string iface; |
| util::Properties<double> properties; |
| msg.read(iface, properties); |
| |
| propertiesChanged(sensor, properties); |
| } |
| |
| void Tach::propertiesChanged(size_t sensor, |
| const util::Properties<double>& props) |
| { |
| // Find the Value property containing the speed. |
| auto it = props.find(tachProperty); |
| if (it != props.end()) |
| { |
| auto& s = state[sensor]; |
| std::get<double>(s) = std::get<double>(it->second); |
| |
| auto newState = |
| std::any_of(state.begin(), state.end(), |
| [](const auto& s) { return std::get<double>(s) != 0; }); |
| |
| if (currentState != newState) |
| { |
| getPolicy().stateChanged(newState, *this); |
| currentState = newState; |
| } |
| } |
| } |
| |
| void Tach::logConflict(const std::string& fanInventoryPath) const |
| { |
| getLogger().log(std::format( |
| "Tach sensor presence detect for fan {} said not present but " |
| "other methods indicated present", |
| fanInventoryPath)); |
| |
| // Let the code that monitors fan faults create the event |
| // logs for stopped rotors. |
| } |
| |
| } // namespace presence |
| } // namespace fan |
| } // namespace phosphor |