/** * 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 #include #include #include #include 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& 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(s); // Register for signal callbacks. std::get<1>(s) = std::make_unique( 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(s) = util::SDBusPlus::getProperty( tachPath, tachIface, tachProperty); } catch (const std::exception&) { // Assume not spinning. std::get(s) = 0; log( fmt::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(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 values; for (const auto& s : state) { values.push_back(util::SDBusPlus::getProperty( tachNamespace + std::get(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::message& msg) { std::string iface; util::Properties properties; msg.read(iface, properties); propertiesChanged(sensor, properties); } void Tach::propertiesChanged(size_t sensor, const util::Properties& props) { // Find the Value property containing the speed. auto it = props.find(tachProperty); if (it != props.end()) { auto& s = state[sensor]; std::get(s) = std::get(it->second); auto newState = std::any_of(state.begin(), state.end(), [](const auto& s) { return std::get(s) != 0; }); if (currentState != newState) { getPolicy().stateChanged(newState, *this); currentState = newState; } } } void Tach::logConflict(const std::string& fanInventoryPath) const { getLogger().log(fmt::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