1 /** 2 * Copyright © 2017 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "tach.hpp" 17 18 #include "logging.hpp" 19 #include "rpolicy.hpp" 20 21 #include <fmt/format.h> 22 23 #include <phosphor-logging/log.hpp> 24 25 #include <string> 26 #include <tuple> 27 #include <vector> 28 29 namespace phosphor 30 { 31 namespace fan 32 { 33 namespace presence 34 { 35 36 using namespace phosphor::logging; 37 using namespace std::literals::string_literals; 38 39 static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s; 40 static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s; 41 static const auto tachProperty = "Value"s; 42 43 Tach::Tach(const std::vector<std::string>& sensors) : currentState(false) 44 { 45 // Initialize state. 46 for (const auto& s : sensors) 47 { 48 state.emplace_back(s, nullptr, 0); 49 } 50 } 51 52 bool Tach::start() 53 { 54 for (size_t i = 0; i < state.size(); ++i) 55 { 56 auto& s = state[i]; 57 auto tachPath = tachNamespace + std::get<std::string>(s); 58 59 // Register for signal callbacks. 60 std::get<1>(s) = std::make_unique<sdbusplus::bus::match_t>( 61 util::SDBusPlus::getBus(), 62 sdbusplus::bus::match::rules::propertiesChanged(tachPath, 63 tachIface), 64 [this, i](auto& msg) { this->propertiesChanged(i, msg); }); 65 66 // Get an initial tach speed. 67 try 68 { 69 std::get<double>(s) = util::SDBusPlus::getProperty<double>( 70 tachPath, tachIface, tachProperty); 71 } 72 catch (const std::exception&) 73 { 74 // Assume not spinning. 75 76 std::get<double>(s) = 0; 77 log<level::INFO>( 78 fmt::format("Unable to read fan tach sensor {}", tachPath) 79 .c_str()); 80 } 81 } 82 83 // Set the initial state of the sensor. 84 currentState = std::any_of(state.begin(), state.end(), [](const auto& s) { 85 return std::get<double>(s) != 0; 86 }); 87 88 return currentState; 89 } 90 91 void Tach::stop() 92 { 93 for (auto& s : state) 94 { 95 // De-register signal callbacks. 96 std::get<1>(s) = nullptr; 97 } 98 } 99 100 bool Tach::present() 101 { 102 // Live query the tach readings. 103 std::vector<double> values; 104 for (const auto& s : state) 105 { 106 values.push_back(util::SDBusPlus::getProperty<double>( 107 tachNamespace + std::get<std::string>(s), tachIface, tachProperty)); 108 } 109 110 return std::any_of(values.begin(), values.end(), 111 [](const auto& v) { return v != 0; }); 112 } 113 114 void Tach::propertiesChanged(size_t sensor, sdbusplus::message_t& msg) 115 { 116 std::string iface; 117 util::Properties<double> properties; 118 msg.read(iface, properties); 119 120 propertiesChanged(sensor, properties); 121 } 122 123 void Tach::propertiesChanged(size_t sensor, 124 const util::Properties<double>& props) 125 { 126 // Find the Value property containing the speed. 127 auto it = props.find(tachProperty); 128 if (it != props.end()) 129 { 130 auto& s = state[sensor]; 131 std::get<double>(s) = std::get<double>(it->second); 132 133 auto newState = 134 std::any_of(state.begin(), state.end(), 135 [](const auto& s) { return std::get<double>(s) != 0; }); 136 137 if (currentState != newState) 138 { 139 getPolicy().stateChanged(newState, *this); 140 currentState = newState; 141 } 142 } 143 } 144 145 void Tach::logConflict(const std::string& fanInventoryPath) const 146 { 147 getLogger().log(fmt::format( 148 "Tach sensor presence detect for fan {} said not present but " 149 "other methods indicated present", 150 fanInventoryPath)); 151 152 // Let the code that monitors fan faults create the event 153 // logs for stopped rotors. 154 } 155 156 } // namespace presence 157 } // namespace fan 158 } // namespace phosphor 159