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