blob: 6c7143a153b7652251901e995bfac3145317ad67 [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{
Brad Bishop8e942502017-07-11 00:35:53 -0400148 // Use the Value interface since not all sensors implement
149 // the control interface.
Matt Spinlerebaae612017-04-27 14:21:48 -0500150 return phosphor::fan::util::getService(_name,
Brad Bishop8e942502017-07-11 00:35:53 -0400151 FAN_SENSOR_VALUE_INTF,
Matt Spinlerebaae612017-04-27 14:21:48 -0500152 _bus);
153}
154
155
156std::string TachSensor::getMatchString(const std::string& interface)
157{
158 return std::string("type='signal',"
159 "interface='org.freedesktop.DBus.Properties',"
160 "member='PropertiesChanged',"
161 "arg0namespace='" + interface + "',"
162 "path='" + _name + "'");
163}
164
165
166int TachSensor::handleTachChangeSignal(sd_bus_message* msg,
167 void* usrData,
168 sd_bus_error* err)
169{
170 auto m = sdbusplus::message::message(msg);
171 static_cast<TachSensor*>(usrData)->handleTachChange(m, err);
172 return 0;
173}
174
175
176int TachSensor::handleTargetChangeSignal(sd_bus_message* msg,
177 void* usrData,
178 sd_bus_error* err)
179{
180 auto m = sdbusplus::message::message(msg);
181 static_cast<TachSensor*>(usrData)->handleTargetChange(m, err);
182 return 0;
183}
184
185
186/**
187 * @brief Reads a property from the input message and stores it in value.
188 * T is the value type.
189 *
190 * Note: This can only be called once per message.
191 *
192 * @param[in] msg - the dbus message that contains the data
193 * @param[in] interface - the interface the property is on
194 * @param[in] propertName - the name of the property
195 * @param[out] value - the value to store the property value in
196 */
197template<typename T>
198static void readPropertyFromMessage(sdbusplus::message::message& msg,
199 const std::string& interface,
200 const std::string& propertyName,
201 T& value)
202{
203 std::string sensor;
204 std::map<std::string, sdbusplus::message::variant<T>> data;
205 msg.read(sensor, data);
206
207 if (sensor.compare(interface) == 0)
208 {
209 auto propertyMap = data.find(propertyName);
210 if (propertyMap != data.end())
211 {
212 value = sdbusplus::message::variant_ns::get<T>(
213 propertyMap->second);
214 }
215 }
216}
217
218
219void TachSensor::handleTargetChange(sdbusplus::message::message& msg,
220 sd_bus_error* err)
221{
222 readPropertyFromMessage(msg,
223 FAN_SENSOR_CONTROL_INTF,
224 FAN_TARGET_PROPERTY,
225 _tachTarget);
226
227 //Check all tach sensors on the fan against the target
228 _fan.tachChanged();
229}
230
231
232void TachSensor::handleTachChange(sdbusplus::message::message& msg,
233 sd_bus_error* err)
234{
235 readPropertyFromMessage(msg,
236 FAN_SENSOR_VALUE_INTF,
237 FAN_VALUE_PROPERTY,
238 _tachInput);
239
240 //Check just this sensor against the target
241 _fan.tachChanged(*this);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500242}
243
244
Matt Spinlera9406a72017-04-27 14:29:24 -0500245std::chrono::microseconds TachSensor::getTimeout()
246{
247 using namespace std::chrono;
248
249 return duration_cast<microseconds>(seconds(_timeout));
250}
251
252
Matt Spinlerabf8da32017-04-27 14:08:45 -0500253}
254}
255}