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