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