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 FAN_SENSOR_CONTROL_INTF = "xyz.openbmc_project.Control.FanSpeed"; 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 35 /** 36 * @brief Helper function to read a property 37 * 38 * @param[in] interface - the interface the property is on 39 * @param[in] propertName - the name of the property 40 * @param[in] path - the dbus path 41 * @param[in] bus - the dbus object 42 * @param[out] value - filled in with the property value 43 */ 44 template<typename T> 45 static void readProperty(const std::string& interface, 46 const std::string& propertyName, 47 const std::string& path, 48 sdbusplus::bus::bus& bus, 49 T& value) 50 { 51 try 52 { 53 value = util::SDBusPlus::getProperty<T>(bus, 54 path, 55 interface, 56 propertyName); 57 } 58 catch (std::exception& e) 59 { 60 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 61 } 62 } 63 64 65 TachSensor::TachSensor(sdbusplus::bus::bus& bus, 66 Fan& fan, 67 const std::string& id, 68 bool hasTarget, 69 size_t timeout, 70 phosphor::fan::event::EventPtr& events) : 71 _bus(bus), 72 _fan(fan), 73 _name(FAN_SENSOR_PATH + id), 74 _hasTarget(hasTarget), 75 _timeout(timeout), 76 _timer(events, [this, &fan](){ fan.timerExpired(*this); }) 77 { 78 //Load in starting Target and Input values 79 80 try 81 { 82 // Use getProperty directly to allow a missing sensor object 83 // to abort construction. 84 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>( 85 _bus, 86 _name, 87 FAN_SENSOR_VALUE_INTF, 88 FAN_VALUE_PROPERTY); 89 } 90 catch (std::exception& e) 91 { 92 throw InvalidSensorError(); 93 } 94 95 if (_hasTarget) 96 { 97 readProperty(FAN_SENSOR_CONTROL_INTF, 98 FAN_TARGET_PROPERTY, 99 _name, 100 _bus, 101 _tachTarget); 102 } 103 104 auto match = getMatchString(FAN_SENSOR_VALUE_INTF); 105 106 tachSignal = std::make_unique<sdbusplus::server::match::match>( 107 _bus, 108 match.c_str(), 109 [this](auto& msg){ this->handleTachChange(msg); }); 110 111 if (_hasTarget) 112 { 113 match = getMatchString(FAN_SENSOR_CONTROL_INTF); 114 115 targetSignal = std::make_unique<sdbusplus::server::match::match>( 116 _bus, 117 match.c_str(), 118 [this](auto& msg){ this->handleTargetChange(msg); }); 119 } 120 121 } 122 123 124 std::string TachSensor::getMatchString(const std::string& interface) 125 { 126 return sdbusplus::bus::match::rules::propertiesChanged( 127 _name, interface); 128 } 129 130 131 /** 132 * @brief Reads a property from the input message and stores it in value. 133 * T is the value type. 134 * 135 * Note: This can only be called once per message. 136 * 137 * @param[in] msg - the dbus message that contains the data 138 * @param[in] interface - the interface the property is on 139 * @param[in] propertName - the name of the property 140 * @param[out] value - the value to store the property value in 141 */ 142 template<typename T> 143 static void readPropertyFromMessage(sdbusplus::message::message& msg, 144 const std::string& interface, 145 const std::string& propertyName, 146 T& value) 147 { 148 std::string sensor; 149 std::map<std::string, sdbusplus::message::variant<T>> data; 150 msg.read(sensor, data); 151 152 if (sensor.compare(interface) == 0) 153 { 154 auto propertyMap = data.find(propertyName); 155 if (propertyMap != data.end()) 156 { 157 value = sdbusplus::message::variant_ns::get<T>( 158 propertyMap->second); 159 } 160 } 161 } 162 163 164 void TachSensor::handleTargetChange(sdbusplus::message::message& msg) 165 { 166 readPropertyFromMessage(msg, 167 FAN_SENSOR_CONTROL_INTF, 168 FAN_TARGET_PROPERTY, 169 _tachTarget); 170 171 //Check all tach sensors on the fan against the target 172 _fan.tachChanged(); 173 } 174 175 176 void TachSensor::handleTachChange(sdbusplus::message::message& msg) 177 { 178 readPropertyFromMessage(msg, 179 FAN_SENSOR_VALUE_INTF, 180 FAN_VALUE_PROPERTY, 181 _tachInput); 182 183 //Check just this sensor against the target 184 _fan.tachChanged(*this); 185 } 186 187 188 std::chrono::microseconds TachSensor::getTimeout() 189 { 190 using namespace std::chrono; 191 192 return duration_cast<microseconds>(seconds(_timeout)); 193 } 194 195 196 } 197 } 198 } 199