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