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 <experimental/filesystem> 17 #include <phosphor-logging/log.hpp> 18 #include "fan.hpp" 19 #include "sdbusplus.hpp" 20 #include "tach_sensor.hpp" 21 #include "utility.hpp" 22 23 namespace phosphor 24 { 25 namespace fan 26 { 27 namespace monitor 28 { 29 30 constexpr auto FAN_SENSOR_CONTROL_INTF = "xyz.openbmc_project.Control.FanSpeed"; 31 constexpr auto FAN_SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value"; 32 constexpr auto FAN_TARGET_PROPERTY = "Target"; 33 constexpr auto FAN_VALUE_PROPERTY = "Value"; 34 35 using namespace std::experimental::filesystem; 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(Mode mode, 68 sdbusplus::bus::bus& bus, 69 Fan& fan, 70 const std::string& id, 71 bool hasTarget, 72 size_t factor, 73 size_t offset, 74 size_t timeout, 75 phosphor::fan::event::EventPtr& events) : 76 _bus(bus), 77 _fan(fan), 78 _name(FAN_SENSOR_PATH + id), 79 _invName(path(fan.getName()) / id), 80 _hasTarget(hasTarget), 81 _factor(factor), 82 _offset(offset), 83 _timeout(timeout), 84 _timer(events, [this, &fan](){ fan.timerExpired(*this); }) 85 { 86 // Start from a known state of functional 87 setFunctional(true); 88 89 // Load in current Target and Input values when entering monitor mode 90 if (mode != Mode::init) 91 { 92 try 93 { 94 // Use getProperty directly to allow a missing sensor object 95 // to abort construction. 96 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>( 97 _bus, 98 _name, 99 FAN_SENSOR_VALUE_INTF, 100 FAN_VALUE_PROPERTY); 101 } 102 catch (std::exception& e) 103 { 104 throw InvalidSensorError(); 105 } 106 107 if (_hasTarget) 108 { 109 readProperty(FAN_SENSOR_CONTROL_INTF, 110 FAN_TARGET_PROPERTY, 111 _name, 112 _bus, 113 _tachTarget); 114 } 115 116 auto match = getMatchString(FAN_SENSOR_VALUE_INTF); 117 118 tachSignal = std::make_unique<sdbusplus::server::match::match>( 119 _bus, 120 match.c_str(), 121 [this](auto& msg){ this->handleTachChange(msg); }); 122 123 if (_hasTarget) 124 { 125 match = getMatchString(FAN_SENSOR_CONTROL_INTF); 126 127 targetSignal = std::make_unique<sdbusplus::server::match::match>( 128 _bus, 129 match.c_str(), 130 [this](auto& msg){ this->handleTargetChange(msg); }); 131 } 132 } 133 } 134 135 std::string TachSensor::getMatchString(const std::string& interface) 136 { 137 return sdbusplus::bus::match::rules::propertiesChanged( 138 _name, interface); 139 } 140 141 uint64_t TachSensor::getTarget() const 142 { 143 if (!_hasTarget) 144 { 145 return _fan.findTargetSpeed(); 146 } 147 return _tachTarget; 148 } 149 150 void TachSensor::setFunctional(bool functional) 151 { 152 _functional = functional; 153 updateInventory(_functional); 154 } 155 156 /** 157 * @brief Reads a property from the input message and stores it in value. 158 * T is the value type. 159 * 160 * Note: This can only be called once per message. 161 * 162 * @param[in] msg - the dbus message that contains the data 163 * @param[in] interface - the interface the property is on 164 * @param[in] propertName - the name of the property 165 * @param[out] value - the value to store the property value in 166 */ 167 template<typename T> 168 static void readPropertyFromMessage(sdbusplus::message::message& msg, 169 const std::string& interface, 170 const std::string& propertyName, 171 T& value) 172 { 173 std::string sensor; 174 std::map<std::string, sdbusplus::message::variant<T>> data; 175 msg.read(sensor, data); 176 177 if (sensor.compare(interface) == 0) 178 { 179 auto propertyMap = data.find(propertyName); 180 if (propertyMap != data.end()) 181 { 182 value = sdbusplus::message::variant_ns::get<T>( 183 propertyMap->second); 184 } 185 } 186 } 187 188 189 void TachSensor::handleTargetChange(sdbusplus::message::message& msg) 190 { 191 readPropertyFromMessage(msg, 192 FAN_SENSOR_CONTROL_INTF, 193 FAN_TARGET_PROPERTY, 194 _tachTarget); 195 196 //Check all tach sensors on the fan against the target 197 _fan.tachChanged(); 198 } 199 200 201 void TachSensor::handleTachChange(sdbusplus::message::message& msg) 202 { 203 readPropertyFromMessage(msg, 204 FAN_SENSOR_VALUE_INTF, 205 FAN_VALUE_PROPERTY, 206 _tachInput); 207 208 //Check just this sensor against the target 209 _fan.tachChanged(*this); 210 } 211 212 213 std::chrono::microseconds TachSensor::getTimeout() 214 { 215 using namespace std::chrono; 216 217 return duration_cast<microseconds>(seconds(_timeout)); 218 } 219 220 void TachSensor::updateInventory(bool functional) 221 { 222 auto objectMap = util::getObjMap<bool>( 223 _invName, 224 util::OPERATIONAL_STATUS_INTF, 225 util::FUNCTIONAL_PROPERTY, 226 functional); 227 auto response = util::SDBusPlus::lookupAndCallMethod( 228 _bus, 229 util::INVENTORY_PATH, 230 util::INVENTORY_INTF, 231 "Notify", 232 objectMap); 233 if (response.is_method_error()) 234 { 235 log<level::ERR>("Error in notify update of tach sensor inventory"); 236 } 237 } 238 239 } 240 } 241 } 242