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_VALUE_INTF = "xyz.openbmc_project.Sensor.Value"; 31 constexpr auto FAN_TARGET_PROPERTY = "Target"; 32 constexpr auto FAN_VALUE_PROPERTY = "Value"; 33 34 using namespace std::experimental::filesystem; 35 36 /** 37 * @brief Helper function to read a property 38 * 39 * @param[in] interface - the interface the property is on 40 * @param[in] propertName - the name of the property 41 * @param[in] path - the dbus path 42 * @param[in] bus - the dbus object 43 * @param[out] value - filled in with the property value 44 */ 45 template<typename T> 46 static void readProperty(const std::string& interface, 47 const std::string& propertyName, 48 const std::string& path, 49 sdbusplus::bus::bus& bus, 50 T& value) 51 { 52 try 53 { 54 value = util::SDBusPlus::getProperty<T>(bus, 55 path, 56 interface, 57 propertyName); 58 } 59 catch (std::exception& e) 60 { 61 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 62 } 63 } 64 65 66 TachSensor::TachSensor(Mode mode, 67 sdbusplus::bus::bus& bus, 68 Fan& fan, 69 const std::string& id, 70 bool hasTarget, 71 size_t funcDelay, 72 const std::string& interface, 73 size_t factor, 74 size_t offset, 75 size_t timeout, 76 phosphor::fan::event::EventPtr& events) : 77 _bus(bus), 78 _fan(fan), 79 _name(FAN_SENSOR_PATH + id), 80 _invName(path(fan.getName()) / id), 81 _hasTarget(hasTarget), 82 _funcDelay(funcDelay), 83 _interface(interface), 84 _factor(factor), 85 _offset(offset), 86 _timeout(timeout), 87 _timer(events, [this, &fan](){ fan.timerExpired(*this); }) 88 { 89 // Start from a known state of functional 90 setFunctional(true); 91 92 // Load in current Target and Input values when entering monitor mode 93 if (mode != Mode::init) 94 { 95 try 96 { 97 // Use getProperty directly to allow a missing sensor object 98 // to abort construction. 99 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>( 100 _bus, 101 _name, 102 FAN_SENSOR_VALUE_INTF, 103 FAN_VALUE_PROPERTY); 104 } 105 catch (std::exception& e) 106 { 107 throw InvalidSensorError(); 108 } 109 110 if (_hasTarget) 111 { 112 readProperty(_interface, 113 FAN_TARGET_PROPERTY, 114 _name, 115 _bus, 116 _tachTarget); 117 } 118 119 auto match = getMatchString(FAN_SENSOR_VALUE_INTF); 120 121 tachSignal = std::make_unique<sdbusplus::server::match::match>( 122 _bus, 123 match.c_str(), 124 [this](auto& msg){ this->handleTachChange(msg); }); 125 126 if (_hasTarget) 127 { 128 match = getMatchString(_interface); 129 130 targetSignal = std::make_unique<sdbusplus::server::match::match>( 131 _bus, 132 match.c_str(), 133 [this](auto& msg){ this->handleTargetChange(msg); }); 134 } 135 } 136 } 137 138 std::string TachSensor::getMatchString(const std::string& interface) 139 { 140 return sdbusplus::bus::match::rules::propertiesChanged( 141 _name, interface); 142 } 143 144 uint64_t TachSensor::getTarget() const 145 { 146 if (!_hasTarget) 147 { 148 return _fan.findTargetSpeed(); 149 } 150 return _tachTarget; 151 } 152 153 void TachSensor::setFunctional(bool functional) 154 { 155 _functional = functional; 156 updateInventory(_functional); 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 { 194 readPropertyFromMessage(msg, 195 _interface, 196 FAN_TARGET_PROPERTY, 197 _tachTarget); 198 199 //Check all tach sensors on the fan against the target 200 _fan.tachChanged(); 201 } 202 203 204 void TachSensor::handleTachChange(sdbusplus::message::message& msg) 205 { 206 readPropertyFromMessage(msg, 207 FAN_SENSOR_VALUE_INTF, 208 FAN_VALUE_PROPERTY, 209 _tachInput); 210 211 //Check just this sensor against the target 212 _fan.tachChanged(*this); 213 } 214 215 216 std::chrono::microseconds TachSensor::getTimeout() 217 { 218 using namespace std::chrono; 219 220 return duration_cast<microseconds>(seconds(_timeout)); 221 } 222 223 void TachSensor::updateInventory(bool functional) 224 { 225 auto objectMap = util::getObjMap<bool>( 226 _invName, 227 util::OPERATIONAL_STATUS_INTF, 228 util::FUNCTIONAL_PROPERTY, 229 functional); 230 auto response = util::SDBusPlus::lookupAndCallMethod( 231 _bus, 232 util::INVENTORY_PATH, 233 util::INVENTORY_INTF, 234 "Notify", 235 objectMap); 236 if (response.is_method_error()) 237 { 238 log<level::ERR>("Error in notify update of tach sensor inventory"); 239 } 240 } 241 242 } 243 } 244 } 245