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 "fan.hpp" 18 #include "sdbusplus.hpp" 19 #include "tach_sensor.hpp" 20 #include "../utility.hpp" 21 22 namespace phosphor 23 { 24 namespace fan 25 { 26 namespace monitor 27 { 28 29 constexpr auto PROPERTY_INTF = "org.freedesktop.DBus.Properties"; 30 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/"; 31 constexpr auto FAN_SENSOR_CONTROL_INTF = "xyz.openbmc_project.Control.FanSpeed"; 32 constexpr auto FAN_SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value"; 33 constexpr auto FAN_TARGET_PROPERTY = "Target"; 34 constexpr auto FAN_VALUE_PROPERTY = "Value"; 35 36 37 /** 38 * @brief Helper function to read a property 39 * 40 * @param[in] interface - the interface the property is on 41 * @param[in] propertName - the name of the property 42 * @param[in] path - the dbus path 43 * @param[in] bus - the dbus object 44 * @param[out] value - filled in with the property value 45 */ 46 template<typename T> 47 static void readProperty(const std::string& interface, 48 const std::string& propertyName, 49 const std::string& path, 50 sdbusplus::bus::bus& bus, 51 T& value) 52 { 53 try 54 { 55 value = util::SDBusPlus::getProperty<T>(bus, 56 path, 57 interface, 58 propertyName); 59 } 60 catch (std::exception& e) 61 { 62 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 63 } 64 } 65 66 67 TachSensor::TachSensor(sdbusplus::bus::bus& bus, 68 Fan& fan, 69 const std::string& id, 70 bool hasTarget, 71 size_t timeout, 72 phosphor::fan::event::EventPtr& events) : 73 _bus(bus), 74 _fan(fan), 75 _name(FAN_SENSOR_PATH + id), 76 _hasTarget(hasTarget), 77 _timeout(timeout), 78 _timer(events, [this, &fan](){ fan.timerExpired(*this); }) 79 { 80 //Load in starting Target and Input values 81 readProperty(FAN_SENSOR_VALUE_INTF, 82 FAN_VALUE_PROPERTY, 83 _name, 84 _bus, 85 _tachInput); 86 87 if (_hasTarget) 88 { 89 readProperty(FAN_SENSOR_CONTROL_INTF, 90 FAN_TARGET_PROPERTY, 91 _name, 92 _bus, 93 _tachTarget); 94 } 95 96 auto match = getMatchString(FAN_SENSOR_VALUE_INTF); 97 98 tachSignal = std::make_unique<sdbusplus::server::match::match>( 99 _bus, 100 match.c_str(), 101 handleTachChangeSignal, 102 this); 103 104 if (_hasTarget) 105 { 106 match = getMatchString(FAN_SENSOR_CONTROL_INTF); 107 108 targetSignal = std::make_unique<sdbusplus::server::match::match>( 109 _bus, 110 match.c_str(), 111 handleTargetChangeSignal, 112 this); 113 } 114 115 } 116 117 118 //Can cache this value after openbmc/openbmc#1496 is resolved 119 std::string TachSensor::getService() 120 { 121 // Use the Value interface since not all sensors implement 122 // the control interface. 123 return phosphor::fan::util::getService(_name, 124 FAN_SENSOR_VALUE_INTF, 125 _bus); 126 } 127 128 129 std::string TachSensor::getMatchString(const std::string& interface) 130 { 131 return std::string("type='signal'," 132 "interface='org.freedesktop.DBus.Properties'," 133 "member='PropertiesChanged'," 134 "arg0namespace='" + interface + "'," 135 "path='" + _name + "'"); 136 } 137 138 139 int TachSensor::handleTachChangeSignal(sd_bus_message* msg, 140 void* usrData, 141 sd_bus_error* err) 142 { 143 auto m = sdbusplus::message::message(msg); 144 static_cast<TachSensor*>(usrData)->handleTachChange(m, err); 145 return 0; 146 } 147 148 149 int TachSensor::handleTargetChangeSignal(sd_bus_message* msg, 150 void* usrData, 151 sd_bus_error* err) 152 { 153 auto m = sdbusplus::message::message(msg); 154 static_cast<TachSensor*>(usrData)->handleTargetChange(m, err); 155 return 0; 156 } 157 158 159 /** 160 * @brief Reads a property from the input message and stores it in value. 161 * T is the value type. 162 * 163 * Note: This can only be called once per message. 164 * 165 * @param[in] msg - the dbus message that contains the data 166 * @param[in] interface - the interface the property is on 167 * @param[in] propertName - the name of the property 168 * @param[out] value - the value to store the property value in 169 */ 170 template<typename T> 171 static void readPropertyFromMessage(sdbusplus::message::message& msg, 172 const std::string& interface, 173 const std::string& propertyName, 174 T& value) 175 { 176 std::string sensor; 177 std::map<std::string, sdbusplus::message::variant<T>> data; 178 msg.read(sensor, data); 179 180 if (sensor.compare(interface) == 0) 181 { 182 auto propertyMap = data.find(propertyName); 183 if (propertyMap != data.end()) 184 { 185 value = sdbusplus::message::variant_ns::get<T>( 186 propertyMap->second); 187 } 188 } 189 } 190 191 192 void TachSensor::handleTargetChange(sdbusplus::message::message& msg, 193 sd_bus_error* err) 194 { 195 readPropertyFromMessage(msg, 196 FAN_SENSOR_CONTROL_INTF, 197 FAN_TARGET_PROPERTY, 198 _tachTarget); 199 200 //Check all tach sensors on the fan against the target 201 _fan.tachChanged(); 202 } 203 204 205 void TachSensor::handleTachChange(sdbusplus::message::message& msg, 206 sd_bus_error* err) 207 { 208 readPropertyFromMessage(msg, 209 FAN_SENSOR_VALUE_INTF, 210 FAN_VALUE_PROPERTY, 211 _tachInput); 212 213 //Check just this sensor against the target 214 _fan.tachChanged(*this); 215 } 216 217 218 std::chrono::microseconds TachSensor::getTimeout() 219 { 220 using namespace std::chrono; 221 222 return duration_cast<microseconds>(seconds(_timeout)); 223 } 224 225 226 } 227 } 228 } 229