blob: d72572970342002a4979f7df278fbbcaada969bb [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>
18#include "fan.hpp"
Brad Bishop2a58e2c2017-07-30 13:49:09 -040019#include "sdbusplus.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050020#include "tach_sensor.hpp"
Matthew Barth4d982852017-11-17 09:37:13 -060021#include "utility.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050022
23namespace phosphor
24{
25namespace fan
26{
27namespace monitor
28{
29
Matt Spinlerebaae612017-04-27 14:21:48 -050030constexpr auto FAN_SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
31constexpr auto FAN_TARGET_PROPERTY = "Target";
32constexpr auto FAN_VALUE_PROPERTY = "Value";
33
Matthew Barth4d982852017-11-17 09:37:13 -060034using namespace std::experimental::filesystem;
Matt Spinlerebaae612017-04-27 14:21:48 -050035
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
Matthew Barth0a9fe162018-01-26 12:53:15 -060066TachSensor::TachSensor(Mode mode,
67 sdbusplus::bus::bus& bus,
Matt Spinlerabf8da32017-04-27 14:08:45 -050068 Fan& fan,
69 const std::string& id,
70 bool hasTarget,
Lei YU80f271b2018-01-31 15:24:46 +080071 const std::string& interface,
Lei YU8e5d1972018-01-26 17:14:00 +080072 size_t factor,
73 size_t offset,
Matt Spinlera9406a72017-04-27 14:29:24 -050074 size_t timeout,
Matt Spinlere824f982017-05-11 10:07:55 -050075 phosphor::fan::event::EventPtr& events) :
Matt Spinlerabf8da32017-04-27 14:08:45 -050076 _bus(bus),
77 _fan(fan),
78 _name(FAN_SENSOR_PATH + id),
Matthew Barth4d982852017-11-17 09:37:13 -060079 _invName(path(fan.getName()) / id),
Matt Spinlerabf8da32017-04-27 14:08:45 -050080 _hasTarget(hasTarget),
Lei YU80f271b2018-01-31 15:24:46 +080081 _interface(interface),
Lei YU8e5d1972018-01-26 17:14:00 +080082 _factor(factor),
83 _offset(offset),
Matt Spinlera9406a72017-04-27 14:29:24 -050084 _timeout(timeout),
85 _timer(events, [this, &fan](){ fan.timerExpired(*this); })
Matt Spinlerabf8da32017-04-27 14:08:45 -050086{
Matthew Barthd199dcd2017-11-20 10:36:41 -060087 // Start from a known state of functional
Matthew Barth7f7df312018-01-15 16:27:50 -060088 setFunctional(true);
Brad Bishopedaeb312017-07-30 19:38:20 -040089
Matthew Barth0a9fe162018-01-26 12:53:15 -060090 // Load in current Target and Input values when entering monitor mode
91 if (mode != Mode::init)
Brad Bishopedaeb312017-07-30 19:38:20 -040092 {
Matthew Barth0a9fe162018-01-26 12:53:15 -060093 try
94 {
95 // Use getProperty directly to allow a missing sensor object
96 // to abort construction.
97 _tachInput = util::SDBusPlus::getProperty<decltype(_tachInput)>(
98 _bus,
99 _name,
100 FAN_SENSOR_VALUE_INTF,
101 FAN_VALUE_PROPERTY);
102 }
103 catch (std::exception& e)
104 {
105 throw InvalidSensorError();
106 }
107
108 if (_hasTarget)
109 {
Lei YU80f271b2018-01-31 15:24:46 +0800110 readProperty(_interface,
Matthew Barth0a9fe162018-01-26 12:53:15 -0600111 FAN_TARGET_PROPERTY,
112 _name,
113 _bus,
114 _tachTarget);
115 }
116
117 auto match = getMatchString(FAN_SENSOR_VALUE_INTF);
118
119 tachSignal = std::make_unique<sdbusplus::server::match::match>(
Brad Bishopedaeb312017-07-30 19:38:20 -0400120 _bus,
Matthew Barth0a9fe162018-01-26 12:53:15 -0600121 match.c_str(),
122 [this](auto& msg){ this->handleTachChange(msg); });
123
124 if (_hasTarget)
125 {
Lei YU80f271b2018-01-31 15:24:46 +0800126 match = getMatchString(_interface);
Matthew Barth0a9fe162018-01-26 12:53:15 -0600127
128 targetSignal = std::make_unique<sdbusplus::server::match::match>(
129 _bus,
130 match.c_str(),
131 [this](auto& msg){ this->handleTargetChange(msg); });
132 }
Brad Bishopedaeb312017-07-30 19:38:20 -0400133 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500134}
135
Matt Spinlerebaae612017-04-27 14:21:48 -0500136std::string TachSensor::getMatchString(const std::string& interface)
137{
Brad Bishop78b58452017-07-30 19:44:49 -0400138 return sdbusplus::bus::match::rules::propertiesChanged(
139 _name, interface);
Matt Spinlerebaae612017-04-27 14:21:48 -0500140}
141
Matthew Barthf552ea52018-01-15 16:22:04 -0600142uint64_t TachSensor::getTarget() const
143{
144 if (!_hasTarget)
145 {
146 return _fan.findTargetSpeed();
147 }
148 return _tachTarget;
149}
150
Matthew Barthd199dcd2017-11-20 10:36:41 -0600151void TachSensor::setFunctional(bool functional)
152{
153 _functional = functional;
154 updateInventory(_functional);
155}
Matt Spinlerebaae612017-04-27 14:21:48 -0500156
Matt Spinlerebaae612017-04-27 14:21:48 -0500157/**
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
Brad Bishop771659f2017-07-30 19:52:21 -0400190void TachSensor::handleTargetChange(sdbusplus::message::message& msg)
Matt Spinlerebaae612017-04-27 14:21:48 -0500191{
192 readPropertyFromMessage(msg,
Lei YU80f271b2018-01-31 15:24:46 +0800193 _interface,
Matt Spinlerebaae612017-04-27 14:21:48 -0500194 FAN_TARGET_PROPERTY,
195 _tachTarget);
196
197 //Check all tach sensors on the fan against the target
198 _fan.tachChanged();
199}
200
201
Brad Bishop771659f2017-07-30 19:52:21 -0400202void TachSensor::handleTachChange(sdbusplus::message::message& msg)
Matt Spinlerebaae612017-04-27 14:21:48 -0500203{
204 readPropertyFromMessage(msg,
205 FAN_SENSOR_VALUE_INTF,
206 FAN_VALUE_PROPERTY,
207 _tachInput);
208
209 //Check just this sensor against the target
210 _fan.tachChanged(*this);
Matt Spinlerabf8da32017-04-27 14:08:45 -0500211}
212
213
Matt Spinlera9406a72017-04-27 14:29:24 -0500214std::chrono::microseconds TachSensor::getTimeout()
215{
216 using namespace std::chrono;
217
218 return duration_cast<microseconds>(seconds(_timeout));
219}
220
Matthew Barth4d982852017-11-17 09:37:13 -0600221void TachSensor::updateInventory(bool functional)
222{
223 auto objectMap = util::getObjMap<bool>(
224 _invName,
225 util::OPERATIONAL_STATUS_INTF,
226 util::FUNCTIONAL_PROPERTY,
227 functional);
228 auto response = util::SDBusPlus::lookupAndCallMethod(
229 _bus,
230 util::INVENTORY_PATH,
231 util::INVENTORY_INTF,
232 "Notify",
233 objectMap);
234 if (response.is_method_error())
235 {
236 log<level::ERR>("Error in notify update of tach sensor inventory");
237 }
238}
Matt Spinlera9406a72017-04-27 14:29:24 -0500239
Matt Spinlerabf8da32017-04-27 14:08:45 -0500240}
241}
242}