blob: 5494450d085ecd9431aefce99e2bf7685a27fa02 [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>
William A. Kennington III22c36ab2018-10-30 19:50:57 -070017#include <functional>
Matt Spinlerabf8da32017-04-27 14:08:45 -050018#include <phosphor-logging/log.hpp>
Matthew Barth3800ae72018-02-19 16:08:04 -060019#include <phosphor-logging/elog.hpp>
Matt Spinlerabf8da32017-04-27 14:08:45 -050020#include "fan.hpp"
Brad Bishop2a58e2c2017-07-30 13:49:09 -040021#include "sdbusplus.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050022#include "tach_sensor.hpp"
Matthew Barth4d982852017-11-17 09:37:13 -060023#include "utility.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050024
25namespace phosphor
26{
27namespace fan
28{
29namespace monitor
30{
31
Matt Spinlerebaae612017-04-27 14:21:48 -050032constexpr auto FAN_SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
33constexpr auto FAN_TARGET_PROPERTY = "Target";
34constexpr auto FAN_VALUE_PROPERTY = "Value";
35
Matthew Barth4d982852017-11-17 09:37:13 -060036using namespace std::experimental::filesystem;
Matthew Barth3800ae72018-02-19 16:08:04 -060037using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
38 Error::InternalFailure;
Matt Spinlerebaae612017-04-27 14:21:48 -050039
40/**
41 * @brief Helper function to read a property
42 *
43 * @param[in] interface - the interface the property is on
44 * @param[in] propertName - the name of the property
45 * @param[in] path - the dbus path
Matt Spinlerebaae612017-04-27 14:21:48 -050046 * @param[in] bus - the dbus object
47 * @param[out] value - filled in with the property value
48 */
49template<typename T>
50static void readProperty(const std::string& interface,
51 const std::string& propertyName,
52 const std::string& path,
Matt Spinlerebaae612017-04-27 14:21:48 -050053 sdbusplus::bus::bus& bus,
54 T& value)
55{
Matt Spinlerebaae612017-04-27 14:21:48 -050056 try
57 {
Brad Bishop2a58e2c2017-07-30 13:49:09 -040058 value = util::SDBusPlus::getProperty<T>(bus,
59 path,
60 interface,
61 propertyName);
Matt Spinlerebaae612017-04-27 14:21:48 -050062 }
63 catch (std::exception& e)
64 {
65 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
66 }
67}
Matt Spinlerabf8da32017-04-27 14:08:45 -050068
69
Matthew Barth0a9fe162018-01-26 12:53:15 -060070TachSensor::TachSensor(Mode mode,
71 sdbusplus::bus::bus& bus,
Matt Spinlerabf8da32017-04-27 14:08:45 -050072 Fan& fan,
73 const std::string& id,
74 bool hasTarget,
Matthew Barth9396bcc2018-02-19 14:13:20 -060075 size_t funcDelay,
Lei YU80f271b2018-01-31 15:24:46 +080076 const std::string& interface,
Lei YU8e5d1972018-01-26 17:14:00 +080077 size_t factor,
78 size_t offset,
Matt Spinlera9406a72017-04-27 14:29:24 -050079 size_t timeout,
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070080 const sdeventplus::Event& event) :
Matt Spinlerabf8da32017-04-27 14:08:45 -050081 _bus(bus),
82 _fan(fan),
83 _name(FAN_SENSOR_PATH + id),
Matthew Barth4d982852017-11-17 09:37:13 -060084 _invName(path(fan.getName()) / id),
Matt Spinlerabf8da32017-04-27 14:08:45 -050085 _hasTarget(hasTarget),
Matthew Barth9396bcc2018-02-19 14:13:20 -060086 _funcDelay(funcDelay),
Lei YU80f271b2018-01-31 15:24:46 +080087 _interface(interface),
Lei YU8e5d1972018-01-26 17:14:00 +080088 _factor(factor),
89 _offset(offset),
Matt Spinlera9406a72017-04-27 14:29:24 -050090 _timeout(timeout),
Matthew Barth3800ae72018-02-19 16:08:04 -060091 _timerMode(TimerMode::func),
William A. Kennington III22c36ab2018-10-30 19:50:57 -070092 _timer(event, std::bind(&Fan::timerExpired, &fan, std::ref(*this)))
Matt Spinlerabf8da32017-04-27 14:08:45 -050093{
Matthew Barthd199dcd2017-11-20 10:36:41 -060094 // Start from a known state of functional
Matthew Barth7f7df312018-01-15 16:27:50 -060095 setFunctional(true);
Brad Bishopedaeb312017-07-30 19:38:20 -040096
Matthew Barth0a9fe162018-01-26 12:53:15 -060097 // Load in current Target and Input values when entering monitor mode
98 if (mode != Mode::init)
Brad Bishopedaeb312017-07-30 19:38:20 -040099 {
Matthew Barth0a9fe162018-01-26 12:53:15 -0600100 try
101 {
102 // Use getProperty directly to allow a missing sensor object
103 // to abort construction.
104 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>(
105 _bus,
106 _name,
107 FAN_SENSOR_VALUE_INTF,
108 FAN_VALUE_PROPERTY);
109 }
110 catch (std::exception& e)
111 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500112 log<level::INFO>("Not monitoring a tach sensor",
113 entry("SENSOR=%s", _name.c_str()));
Matthew Barth0a9fe162018-01-26 12:53:15 -0600114 throw InvalidSensorError();
115 }
116
117 if (_hasTarget)
118 {
Lei YU80f271b2018-01-31 15:24:46 +0800119 readProperty(_interface,
Matthew Barth0a9fe162018-01-26 12:53:15 -0600120 FAN_TARGET_PROPERTY,
121 _name,
122 _bus,
123 _tachTarget);
124 }
125
126 auto match = getMatchString(FAN_SENSOR_VALUE_INTF);
127
128 tachSignal = std::make_unique<sdbusplus::server::match::match>(
Brad Bishopedaeb312017-07-30 19:38:20 -0400129 _bus,
Matthew Barth0a9fe162018-01-26 12:53:15 -0600130 match.c_str(),
131 [this](auto& msg){ this->handleTachChange(msg); });
132
133 if (_hasTarget)
134 {
Lei YU80f271b2018-01-31 15:24:46 +0800135 match = getMatchString(_interface);
Matthew Barth0a9fe162018-01-26 12:53:15 -0600136
137 targetSignal = std::make_unique<sdbusplus::server::match::match>(
138 _bus,
139 match.c_str(),
140 [this](auto& msg){ this->handleTargetChange(msg); });
141 }
Brad Bishopedaeb312017-07-30 19:38:20 -0400142 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500143}
144
Matt Spinlerebaae612017-04-27 14:21:48 -0500145std::string TachSensor::getMatchString(const std::string& interface)
146{
Brad Bishop78b58452017-07-30 19:44:49 -0400147 return sdbusplus::bus::match::rules::propertiesChanged(
148 _name, interface);
Matt Spinlerebaae612017-04-27 14:21:48 -0500149}
150
Matthew Barthf552ea52018-01-15 16:22:04 -0600151uint64_t TachSensor::getTarget() const
152{
153 if (!_hasTarget)
154 {
155 return _fan.findTargetSpeed();
156 }
157 return _tachTarget;
158}
159
Matthew Barthd199dcd2017-11-20 10:36:41 -0600160void TachSensor::setFunctional(bool functional)
161{
162 _functional = functional;
163 updateInventory(_functional);
164}
Matt Spinlerebaae612017-04-27 14:21:48 -0500165
Matt Spinlerebaae612017-04-27 14:21:48 -0500166/**
167 * @brief Reads a property from the input message and stores it in value.
168 * T is the value type.
169 *
170 * Note: This can only be called once per message.
171 *
172 * @param[in] msg - the dbus message that contains the data
173 * @param[in] interface - the interface the property is on
174 * @param[in] propertName - the name of the property
175 * @param[out] value - the value to store the property value in
176 */
177template<typename T>
178static void readPropertyFromMessage(sdbusplus::message::message& msg,
179 const std::string& interface,
180 const std::string& propertyName,
181 T& value)
182{
183 std::string sensor;
184 std::map<std::string, sdbusplus::message::variant<T>> data;
185 msg.read(sensor, data);
186
187 if (sensor.compare(interface) == 0)
188 {
189 auto propertyMap = data.find(propertyName);
190 if (propertyMap != data.end())
191 {
192 value = sdbusplus::message::variant_ns::get<T>(
193 propertyMap->second);
194 }
195 }
196}
197
198
Brad Bishop771659f2017-07-30 19:52:21 -0400199void TachSensor::handleTargetChange(sdbusplus::message::message& msg)
Matt Spinlerebaae612017-04-27 14:21:48 -0500200{
201 readPropertyFromMessage(msg,
Lei YU80f271b2018-01-31 15:24:46 +0800202 _interface,
Matt Spinlerebaae612017-04-27 14:21:48 -0500203 FAN_TARGET_PROPERTY,
204 _tachTarget);
205
206 //Check all tach sensors on the fan against the target
207 _fan.tachChanged();
208}
209
210
Brad Bishop771659f2017-07-30 19:52:21 -0400211void TachSensor::handleTachChange(sdbusplus::message::message& msg)
Matt Spinlerebaae612017-04-27 14:21:48 -0500212{
213 readPropertyFromMessage(msg,
214 FAN_SENSOR_VALUE_INTF,
215 FAN_VALUE_PROPERTY,
216 _tachInput);
217
218 //Check just this sensor against the target
219 _fan.tachChanged(*this);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500220}
221
Matthew Barth3800ae72018-02-19 16:08:04 -0600222void TachSensor::startTimer(TimerMode mode)
223{
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700224 if (!timerRunning() || mode != _timerMode)
Matthew Barth3800ae72018-02-19 16:08:04 -0600225 {
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700226 _timer.restartOnce(getDelay(mode));
Matthew Barth3800ae72018-02-19 16:08:04 -0600227 _timerMode = mode;
228 }
Matthew Barth3800ae72018-02-19 16:08:04 -0600229}
Matt Spinlerabf8da32017-04-27 14:08:45 -0500230
Matthew Barth3800ae72018-02-19 16:08:04 -0600231std::chrono::microseconds TachSensor::getDelay(TimerMode mode)
Matt Spinlera9406a72017-04-27 14:29:24 -0500232{
233 using namespace std::chrono;
234
Matthew Barth3800ae72018-02-19 16:08:04 -0600235 switch(mode)
236 {
237 case TimerMode::nonfunc :
238 return duration_cast<microseconds>(seconds(_timeout));
239 case TimerMode::func :
240 return duration_cast<microseconds>(seconds(_funcDelay));
241 default :
242 // Log an internal error for undefined timer mode
243 log<level::ERR>("Undefined timer mode",
244 entry("TIMER_MODE=%u", mode));
245 elog<InternalFailure>();
246 return duration_cast<microseconds>(seconds(0));
247 }
Matt Spinlera9406a72017-04-27 14:29:24 -0500248}
249
Matthew Barth4d982852017-11-17 09:37:13 -0600250void TachSensor::updateInventory(bool functional)
251{
252 auto objectMap = util::getObjMap<bool>(
253 _invName,
254 util::OPERATIONAL_STATUS_INTF,
255 util::FUNCTIONAL_PROPERTY,
256 functional);
257 auto response = util::SDBusPlus::lookupAndCallMethod(
258 _bus,
259 util::INVENTORY_PATH,
260 util::INVENTORY_INTF,
261 "Notify",
262 objectMap);
263 if (response.is_method_error())
264 {
265 log<level::ERR>("Error in notify update of tach sensor inventory");
266 }
267}
Matt Spinlera9406a72017-04-27 14:29:24 -0500268
Matt Spinlerabf8da32017-04-27 14:08:45 -0500269}
270}
271}