blob: a4ebcd9c7e7dc77a78fe987269082fd688030d90 [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"
Brad Bishop2a58e2c2017-07-30 13:49:09 -040018#include "sdbusplus.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050019#include "tach_sensor.hpp"
20#include "../utility.hpp"
21
22namespace phosphor
23{
24namespace fan
25{
26namespace monitor
27{
28
29constexpr 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
Matt Spinlerebaae612017-04-27 14:21:48 -050042 * @param[in] bus - the dbus object
43 * @param[out] value - filled in with the property value
44 */
45template<typename T>
46static void readProperty(const std::string& interface,
47 const std::string& propertyName,
48 const std::string& path,
Matt Spinlerebaae612017-04-27 14:21:48 -050049 sdbusplus::bus::bus& bus,
50 T& value)
51{
Matt Spinlerebaae612017-04-27 14:21:48 -050052 try
53 {
Brad Bishop2a58e2c2017-07-30 13:49:09 -040054 value = util::SDBusPlus::getProperty<T>(bus,
55 path,
56 interface,
57 propertyName);
Matt Spinlerebaae612017-04-27 14:21:48 -050058 }
59 catch (std::exception& e)
60 {
61 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
62 }
63}
Matt Spinlerabf8da32017-04-27 14:08:45 -050064
65
66TachSensor::TachSensor(sdbusplus::bus::bus& bus,
67 Fan& fan,
68 const std::string& id,
69 bool hasTarget,
Matt Spinlera9406a72017-04-27 14:29:24 -050070 size_t timeout,
Matt Spinlere824f982017-05-11 10:07:55 -050071 phosphor::fan::event::EventPtr& events) :
Matt Spinlerabf8da32017-04-27 14:08:45 -050072 _bus(bus),
73 _fan(fan),
74 _name(FAN_SENSOR_PATH + id),
75 _hasTarget(hasTarget),
Matt Spinlera9406a72017-04-27 14:29:24 -050076 _timeout(timeout),
77 _timer(events, [this, &fan](){ fan.timerExpired(*this); })
Matt Spinlerabf8da32017-04-27 14:08:45 -050078{
Matt Spinlerebaae612017-04-27 14:21:48 -050079 //Load in starting Target and Input values
Brad Bishopedaeb312017-07-30 19:38:20 -040080
81 try
82 {
83 // Use getProperty directly to allow a missing sensor object
84 // to abort construction.
85 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>(
86 _bus,
87 _name,
88 FAN_SENSOR_VALUE_INTF,
89 FAN_VALUE_PROPERTY);
90 }
91 catch (std::exception& e)
92 {
93 throw InvalidSensorError();
94 }
Matt Spinlerebaae612017-04-27 14:21:48 -050095
96 if (_hasTarget)
97 {
98 readProperty(FAN_SENSOR_CONTROL_INTF,
99 FAN_TARGET_PROPERTY,
100 _name,
Matt Spinlerebaae612017-04-27 14:21:48 -0500101 _bus,
102 _tachTarget);
103 }
104
105 auto match = getMatchString(FAN_SENSOR_VALUE_INTF);
106
107 tachSignal = std::make_unique<sdbusplus::server::match::match>(
108 _bus,
109 match.c_str(),
110 handleTachChangeSignal,
111 this);
112
113 if (_hasTarget)
114 {
115 match = getMatchString(FAN_SENSOR_CONTROL_INTF);
116
117 targetSignal = std::make_unique<sdbusplus::server::match::match>(
118 _bus,
119 match.c_str(),
120 handleTargetChangeSignal,
121 this);
122 }
123
124}
125
126
Matt Spinlerebaae612017-04-27 14:21:48 -0500127std::string TachSensor::getMatchString(const std::string& interface)
128{
129 return std::string("type='signal',"
130 "interface='org.freedesktop.DBus.Properties',"
131 "member='PropertiesChanged',"
132 "arg0namespace='" + interface + "',"
133 "path='" + _name + "'");
134}
135
136
137int TachSensor::handleTachChangeSignal(sd_bus_message* msg,
138 void* usrData,
139 sd_bus_error* err)
140{
141 auto m = sdbusplus::message::message(msg);
142 static_cast<TachSensor*>(usrData)->handleTachChange(m, err);
143 return 0;
144}
145
146
147int TachSensor::handleTargetChangeSignal(sd_bus_message* msg,
148 void* usrData,
149 sd_bus_error* err)
150{
151 auto m = sdbusplus::message::message(msg);
152 static_cast<TachSensor*>(usrData)->handleTargetChange(m, err);
153 return 0;
154}
155
156
157/**
158 * @brief Reads a property from the input message and stores it in value.
159 * T is the value type.
160 *
161 * Note: This can only be called once per message.
162 *
163 * @param[in] msg - the dbus message that contains the data
164 * @param[in] interface - the interface the property is on
165 * @param[in] propertName - the name of the property
166 * @param[out] value - the value to store the property value in
167 */
168template<typename T>
169static void readPropertyFromMessage(sdbusplus::message::message& msg,
170 const std::string& interface,
171 const std::string& propertyName,
172 T& value)
173{
174 std::string sensor;
175 std::map<std::string, sdbusplus::message::variant<T>> data;
176 msg.read(sensor, data);
177
178 if (sensor.compare(interface) == 0)
179 {
180 auto propertyMap = data.find(propertyName);
181 if (propertyMap != data.end())
182 {
183 value = sdbusplus::message::variant_ns::get<T>(
184 propertyMap->second);
185 }
186 }
187}
188
189
190void TachSensor::handleTargetChange(sdbusplus::message::message& msg,
191 sd_bus_error* err)
192{
193 readPropertyFromMessage(msg,
194 FAN_SENSOR_CONTROL_INTF,
195 FAN_TARGET_PROPERTY,
196 _tachTarget);
197
198 //Check all tach sensors on the fan against the target
199 _fan.tachChanged();
200}
201
202
203void TachSensor::handleTachChange(sdbusplus::message::message& msg,
204 sd_bus_error* err)
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);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500213}
214
215
Matt Spinlera9406a72017-04-27 14:29:24 -0500216std::chrono::microseconds TachSensor::getTimeout()
217{
218 using namespace std::chrono;
219
220 return duration_cast<microseconds>(seconds(_timeout));
221}
222
223
Matt Spinlerabf8da32017-04-27 14:08:45 -0500224}
225}
226}