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