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