blob: 6789ed814b1e88c6fab3e6e70252e7d574810a29 [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 */
Matthew Barth4d982852017-11-17 09:37:13 -060016#include <experimental/filesystem>
Matt Spinlerabf8da32017-04-27 14:08:45 -050017#include <phosphor-logging/log.hpp>
Matthew Barth3800ae72018-02-19 16:08:04 -060018#include <phosphor-logging/elog.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -050019#include "fan.hpp"
Brad Bishop2a58e2c2017-07-30 13:49:09 -040020#include "sdbusplus.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050021#include "tach_sensor.hpp"
Matthew Barth4d982852017-11-17 09:37:13 -060022#include "utility.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050023
24namespace phosphor
25{
26namespace fan
27{
28namespace monitor
29{
30
Matt Spinlerebaae612017-04-27 14:21:48 -050031constexpr auto FAN_SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
32constexpr auto FAN_TARGET_PROPERTY = "Target";
33constexpr auto FAN_VALUE_PROPERTY = "Value";
34
Matthew Barth4d982852017-11-17 09:37:13 -060035using namespace std::experimental::filesystem;
Matthew Barth3800ae72018-02-19 16:08:04 -060036using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
37 Error::InternalFailure;
Matt Spinlerebaae612017-04-27 14:21:48 -050038
39/**
40 * @brief Helper function to read a property
41 *
42 * @param[in] interface - the interface the property is on
43 * @param[in] propertName - the name of the property
44 * @param[in] path - the dbus path
Matt Spinlerebaae612017-04-27 14:21:48 -050045 * @param[in] bus - the dbus object
46 * @param[out] value - filled in with the property value
47 */
48template<typename T>
49static void readProperty(const std::string& interface,
50 const std::string& propertyName,
51 const std::string& path,
Matt Spinlerebaae612017-04-27 14:21:48 -050052 sdbusplus::bus::bus& bus,
53 T& value)
54{
Matt Spinlerebaae612017-04-27 14:21:48 -050055 try
56 {
Brad Bishop2a58e2c2017-07-30 13:49:09 -040057 value = util::SDBusPlus::getProperty<T>(bus,
58 path,
59 interface,
60 propertyName);
Matt Spinlerebaae612017-04-27 14:21:48 -050061 }
62 catch (std::exception& e)
63 {
64 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
65 }
66}
Matt Spinlerabf8da32017-04-27 14:08:45 -050067
68
Matthew Barth0a9fe162018-01-26 12:53:15 -060069TachSensor::TachSensor(Mode mode,
70 sdbusplus::bus::bus& bus,
Matt Spinlerabf8da32017-04-27 14:08:45 -050071 Fan& fan,
72 const std::string& id,
73 bool hasTarget,
Matthew Barth9396bcc2018-02-19 14:13:20 -060074 size_t funcDelay,
Lei YU80f271b2018-01-31 15:24:46 +080075 const std::string& interface,
Lei YU8e5d1972018-01-26 17:14:00 +080076 size_t factor,
77 size_t offset,
Matt Spinlera9406a72017-04-27 14:29:24 -050078 size_t timeout,
Matt Spinlere824f982017-05-11 10:07:55 -050079 phosphor::fan::event::EventPtr& events) :
Matt Spinlerabf8da32017-04-27 14:08:45 -050080 _bus(bus),
81 _fan(fan),
82 _name(FAN_SENSOR_PATH + id),
Matthew Barth4d982852017-11-17 09:37:13 -060083 _invName(path(fan.getName()) / id),
Matt Spinlerabf8da32017-04-27 14:08:45 -050084 _hasTarget(hasTarget),
Matthew Barth9396bcc2018-02-19 14:13:20 -060085 _funcDelay(funcDelay),
Lei YU80f271b2018-01-31 15:24:46 +080086 _interface(interface),
Lei YU8e5d1972018-01-26 17:14:00 +080087 _factor(factor),
88 _offset(offset),
Matt Spinlera9406a72017-04-27 14:29:24 -050089 _timeout(timeout),
Matthew Barth3800ae72018-02-19 16:08:04 -060090 _timerMode(TimerMode::func),
Matt Spinlera9406a72017-04-27 14:29:24 -050091 _timer(events, [this, &fan](){ fan.timerExpired(*this); })
Matt Spinlerabf8da32017-04-27 14:08:45 -050092{
Matthew Barthd199dcd2017-11-20 10:36:41 -060093 // Start from a known state of functional
Matthew Barth7f7df312018-01-15 16:27:50 -060094 setFunctional(true);
Brad Bishopedaeb312017-07-30 19:38:20 -040095
Matthew Barth0a9fe162018-01-26 12:53:15 -060096 // Load in current Target and Input values when entering monitor mode
97 if (mode != Mode::init)
Brad Bishopedaeb312017-07-30 19:38:20 -040098 {
Matthew Barth0a9fe162018-01-26 12:53:15 -060099 try
100 {
101 // Use getProperty directly to allow a missing sensor object
102 // to abort construction.
103 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>(
104 _bus,
105 _name,
106 FAN_SENSOR_VALUE_INTF,
107 FAN_VALUE_PROPERTY);
108 }
109 catch (std::exception& e)
110 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500111 log<level::INFO>("Not monitoring a tach sensor",
112 entry("SENSOR=%s", _name.c_str()));
Matthew Barth0a9fe162018-01-26 12:53:15 -0600113 throw InvalidSensorError();
114 }
115
116 if (_hasTarget)
117 {
Lei YU80f271b2018-01-31 15:24:46 +0800118 readProperty(_interface,
Matthew Barth0a9fe162018-01-26 12:53:15 -0600119 FAN_TARGET_PROPERTY,
120 _name,
121 _bus,
122 _tachTarget);
123 }
124
125 auto match = getMatchString(FAN_SENSOR_VALUE_INTF);
126
127 tachSignal = std::make_unique<sdbusplus::server::match::match>(
Brad Bishopedaeb312017-07-30 19:38:20 -0400128 _bus,
Matthew Barth0a9fe162018-01-26 12:53:15 -0600129 match.c_str(),
130 [this](auto& msg){ this->handleTachChange(msg); });
131
132 if (_hasTarget)
133 {
Lei YU80f271b2018-01-31 15:24:46 +0800134 match = getMatchString(_interface);
Matthew Barth0a9fe162018-01-26 12:53:15 -0600135
136 targetSignal = std::make_unique<sdbusplus::server::match::match>(
137 _bus,
138 match.c_str(),
139 [this](auto& msg){ this->handleTargetChange(msg); });
140 }
Brad Bishopedaeb312017-07-30 19:38:20 -0400141 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500142}
143
Matt Spinlerebaae612017-04-27 14:21:48 -0500144std::string TachSensor::getMatchString(const std::string& interface)
145{
Brad Bishop78b58452017-07-30 19:44:49 -0400146 return sdbusplus::bus::match::rules::propertiesChanged(
147 _name, interface);
Matt Spinlerebaae612017-04-27 14:21:48 -0500148}
149
Matthew Barthf552ea52018-01-15 16:22:04 -0600150uint64_t TachSensor::getTarget() const
151{
152 if (!_hasTarget)
153 {
154 return _fan.findTargetSpeed();
155 }
156 return _tachTarget;
157}
158
Matthew Barthd199dcd2017-11-20 10:36:41 -0600159void TachSensor::setFunctional(bool functional)
160{
161 _functional = functional;
162 updateInventory(_functional);
163}
Matt Spinlerebaae612017-04-27 14:21:48 -0500164
Matt Spinlerebaae612017-04-27 14:21:48 -0500165/**
166 * @brief Reads a property from the input message and stores it in value.
167 * T is the value type.
168 *
169 * Note: This can only be called once per message.
170 *
171 * @param[in] msg - the dbus message that contains the data
172 * @param[in] interface - the interface the property is on
173 * @param[in] propertName - the name of the property
174 * @param[out] value - the value to store the property value in
175 */
176template<typename T>
177static void readPropertyFromMessage(sdbusplus::message::message& msg,
178 const std::string& interface,
179 const std::string& propertyName,
180 T& value)
181{
182 std::string sensor;
183 std::map<std::string, sdbusplus::message::variant<T>> data;
184 msg.read(sensor, data);
185
186 if (sensor.compare(interface) == 0)
187 {
188 auto propertyMap = data.find(propertyName);
189 if (propertyMap != data.end())
190 {
191 value = sdbusplus::message::variant_ns::get<T>(
192 propertyMap->second);
193 }
194 }
195}
196
197
Brad Bishop771659f2017-07-30 19:52:21 -0400198void TachSensor::handleTargetChange(sdbusplus::message::message& msg)
Matt Spinlerebaae612017-04-27 14:21:48 -0500199{
200 readPropertyFromMessage(msg,
Lei YU80f271b2018-01-31 15:24:46 +0800201 _interface,
Matt Spinlerebaae612017-04-27 14:21:48 -0500202 FAN_TARGET_PROPERTY,
203 _tachTarget);
204
205 //Check all tach sensors on the fan against the target
206 _fan.tachChanged();
207}
208
209
Brad Bishop771659f2017-07-30 19:52:21 -0400210void TachSensor::handleTachChange(sdbusplus::message::message& msg)
Matt Spinlerebaae612017-04-27 14:21:48 -0500211{
212 readPropertyFromMessage(msg,
213 FAN_SENSOR_VALUE_INTF,
214 FAN_VALUE_PROPERTY,
215 _tachInput);
216
217 //Check just this sensor against the target
218 _fan.tachChanged(*this);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500219}
220
Matthew Barth3800ae72018-02-19 16:08:04 -0600221void TachSensor::startTimer(TimerMode mode)
222{
223 if (!timerRunning())
224 {
225 _timer.start(
226 getDelay(mode),
227 util::Timer::TimerType::oneshot);
228 _timerMode = mode;
229 }
230 else
231 {
232 if (mode != _timerMode)
233 {
234 _timer.stop();
235 _timer.start(
236 getDelay(mode),
237 util::Timer::TimerType::oneshot);
238 _timerMode = mode;
239 }
240 }
241}
Matt Spinlerabf8da32017-04-27 14:08:45 -0500242
Matthew Barth3800ae72018-02-19 16:08:04 -0600243std::chrono::microseconds TachSensor::getDelay(TimerMode mode)
Matt Spinlera9406a72017-04-27 14:29:24 -0500244{
245 using namespace std::chrono;
246
Matthew Barth3800ae72018-02-19 16:08:04 -0600247 switch(mode)
248 {
249 case TimerMode::nonfunc :
250 return duration_cast<microseconds>(seconds(_timeout));
251 case TimerMode::func :
252 return duration_cast<microseconds>(seconds(_funcDelay));
253 default :
254 // Log an internal error for undefined timer mode
255 log<level::ERR>("Undefined timer mode",
256 entry("TIMER_MODE=%u", mode));
257 elog<InternalFailure>();
258 return duration_cast<microseconds>(seconds(0));
259 }
Matt Spinlera9406a72017-04-27 14:29:24 -0500260}
261
Matthew Barth4d982852017-11-17 09:37:13 -0600262void TachSensor::updateInventory(bool functional)
263{
264 auto objectMap = util::getObjMap<bool>(
265 _invName,
266 util::OPERATIONAL_STATUS_INTF,
267 util::FUNCTIONAL_PROPERTY,
268 functional);
269 auto response = util::SDBusPlus::lookupAndCallMethod(
270 _bus,
271 util::INVENTORY_PATH,
272 util::INVENTORY_INTF,
273 "Notify",
274 objectMap);
275 if (response.is_method_error())
276 {
277 log<level::ERR>("Error in notify update of tach sensor inventory");
278 }
279}
Matt Spinlera9406a72017-04-27 14:29:24 -0500280
Matt Spinlerabf8da32017-04-27 14:08:45 -0500281}
282}
283}