diff options
-rw-r--r-- | monitor/Makefile.am | 1 | ||||
-rw-r--r-- | monitor/fan.cpp | 15 | ||||
-rw-r--r-- | monitor/fan.hpp | 12 | ||||
-rw-r--r-- | monitor/tach_sensor.cpp | 190 | ||||
-rw-r--r-- | monitor/tach_sensor.hpp | 66 |
5 files changed, 283 insertions, 1 deletions
diff --git a/monitor/Makefile.am b/monitor/Makefile.am index 26b66b5..6c6f4b3 100644 --- a/monitor/Makefile.am +++ b/monitor/Makefile.am @@ -11,6 +11,7 @@ phosphor_fan_monitor_SOURCES = \ tach_sensor.cpp phosphor_fan_monitor_LDADD = \ + $(top_builddir)/libfan.la \ $(SDBUSPLUS_LIBS) \ $(PHOSPHOR_LOGGING_LIBS) diff --git a/monitor/fan.cpp b/monitor/fan.cpp index b29eaab..852d2ba 100644 --- a/monitor/fan.cpp +++ b/monitor/fan.cpp @@ -51,6 +51,21 @@ Fan::Fan(sdbusplus::bus::bus& bus, } +void Fan::tachChanged() +{ + for (auto& s : _sensors) + { + tachChanged(*s); + } +} + + +void Fan::tachChanged(TachSensor& sensor) +{ + //TODO +} + + uint64_t Fan::getTargetSpeed(const TachSensor& sensor) { uint64_t target = 0; diff --git a/monitor/fan.hpp b/monitor/fan.hpp index 6cbd370..d79ae31 100644 --- a/monitor/fan.hpp +++ b/monitor/fan.hpp @@ -66,6 +66,18 @@ class Fan std::shared_ptr<sd_event>& events, const FanDefinition& def); + /** + * @brief Callback function for when an input sensor changes + * + * Starts a timer, where if it expires then the sensor + * was slow for too long and can be considered not functional. + */ + void tachChanged(TachSensor& sensor); + + /** + * @brief Calls tachChanged(sensor) on each sensor + */ + void tachChanged(); private: diff --git a/monitor/tach_sensor.cpp b/monitor/tach_sensor.cpp index 3264ddf..c991bb6 100644 --- a/monitor/tach_sensor.cpp +++ b/monitor/tach_sensor.cpp @@ -25,7 +25,59 @@ namespace fan namespace monitor { +constexpr auto PROPERTY_INTF = "org.freedesktop.DBus.Properties"; constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/"; +constexpr auto FAN_SENSOR_CONTROL_INTF = "xyz.openbmc_project.Control.FanSpeed"; +constexpr auto FAN_SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value"; +constexpr auto FAN_TARGET_PROPERTY = "Target"; +constexpr auto FAN_VALUE_PROPERTY = "Value"; + + +/** + * @brief Helper function to read a property + * + * @param[in] interface - the interface the property is on + * @param[in] propertName - the name of the property + * @param[in] path - the dbus path + * @param[in] service - the dbus service + * @param[in] bus - the dbus object + * @param[out] value - filled in with the property value + */ +template<typename T> +static void readProperty(const std::string& interface, + const std::string& propertyName, + const std::string& path, + const std::string& service, + sdbusplus::bus::bus& bus, + T& value) +{ + sdbusplus::message::variant<T> property; + + try + { + auto method = bus.new_method_call(service.c_str(), + path.c_str(), + PROPERTY_INTF, + "Get"); + + method.append(interface, propertyName); + + auto reply = bus.call(method); + if (reply.is_method_error()) + { + throw std::runtime_error( + "Error in property get call for path " + + path); + } + + reply.read(property); + value = sdbusplus::message::variant_ns::get<T>(property); + } + catch (std::exception& e) + { + phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); + } +} TachSensor::TachSensor(sdbusplus::bus::bus& bus, @@ -40,7 +92,143 @@ TachSensor::TachSensor(sdbusplus::bus::bus& bus, _hasTarget(hasTarget), _timeout(timeout) { - //TODO + auto service = getService(); + + //Load in starting Target and Input values + readProperty(FAN_SENSOR_VALUE_INTF, + FAN_VALUE_PROPERTY, + _name, + service, + _bus, + _tachInput); + + if (_hasTarget) + { + readProperty(FAN_SENSOR_CONTROL_INTF, + FAN_TARGET_PROPERTY, + _name, + service, + _bus, + _tachTarget); + } + + auto match = getMatchString(FAN_SENSOR_VALUE_INTF); + + tachSignal = std::make_unique<sdbusplus::server::match::match>( + _bus, + match.c_str(), + handleTachChangeSignal, + this); + + if (_hasTarget) + { + match = getMatchString(FAN_SENSOR_CONTROL_INTF); + + targetSignal = std::make_unique<sdbusplus::server::match::match>( + _bus, + match.c_str(), + handleTargetChangeSignal, + this); + } + +} + + +//Can cache this value after openbmc/openbmc#1496 is resolved +std::string TachSensor::getService() +{ + return phosphor::fan::util::getService(_name, + FAN_SENSOR_CONTROL_INTF, + _bus); +} + + +std::string TachSensor::getMatchString(const std::string& interface) +{ + return std::string("type='signal'," + "interface='org.freedesktop.DBus.Properties'," + "member='PropertiesChanged'," + "arg0namespace='" + interface + "'," + "path='" + _name + "'"); +} + + +int TachSensor::handleTachChangeSignal(sd_bus_message* msg, + void* usrData, + sd_bus_error* err) +{ + auto m = sdbusplus::message::message(msg); + static_cast<TachSensor*>(usrData)->handleTachChange(m, err); + return 0; +} + + +int TachSensor::handleTargetChangeSignal(sd_bus_message* msg, + void* usrData, + sd_bus_error* err) +{ + auto m = sdbusplus::message::message(msg); + static_cast<TachSensor*>(usrData)->handleTargetChange(m, err); + return 0; +} + + +/** + * @brief Reads a property from the input message and stores it in value. + * T is the value type. + * + * Note: This can only be called once per message. + * + * @param[in] msg - the dbus message that contains the data + * @param[in] interface - the interface the property is on + * @param[in] propertName - the name of the property + * @param[out] value - the value to store the property value in + */ +template<typename T> +static void readPropertyFromMessage(sdbusplus::message::message& msg, + const std::string& interface, + const std::string& propertyName, + T& value) +{ + std::string sensor; + std::map<std::string, sdbusplus::message::variant<T>> data; + msg.read(sensor, data); + + if (sensor.compare(interface) == 0) + { + auto propertyMap = data.find(propertyName); + if (propertyMap != data.end()) + { + value = sdbusplus::message::variant_ns::get<T>( + propertyMap->second); + } + } +} + + +void TachSensor::handleTargetChange(sdbusplus::message::message& msg, + sd_bus_error* err) +{ + readPropertyFromMessage(msg, + FAN_SENSOR_CONTROL_INTF, + FAN_TARGET_PROPERTY, + _tachTarget); + + //Check all tach sensors on the fan against the target + _fan.tachChanged(); +} + + +void TachSensor::handleTachChange(sdbusplus::message::message& msg, + sd_bus_error* err) +{ + readPropertyFromMessage(msg, + FAN_SENSOR_VALUE_INTF, + FAN_VALUE_PROPERTY, + _tachInput); + + //Check just this sensor against the target + _fan.tachChanged(*this); } diff --git a/monitor/tach_sensor.hpp b/monitor/tach_sensor.hpp index df340f5..003763c 100644 --- a/monitor/tach_sensor.hpp +++ b/monitor/tach_sensor.hpp @@ -97,6 +97,62 @@ class TachSensor private: /** + * @brief Returns the service name for reading the sensor + */ + std::string getService(); + + /** + * @brief Returns the match string to use for matching + * on a properties changed signal. + */ + std::string getMatchString(const std::string& interface); + + /** + * @brief Callback function for a tach input properties + * changed signal + * + * @param[in] msg - the dbus message + * @param[in] data - user data + * @param[in] err - dbus error + */ + static int handleTachChangeSignal(sd_bus_message* msg, + void* data, + sd_bus_error* err); + + /** + * @brief Callback function for a Target properties + * changed signal + * + * @param[in] msg - the dbus message + * @param[in] data - user data + * @param[in] err - dbus error + */ + static int handleTargetChangeSignal(sd_bus_message* msg, + void* data, + sd_bus_error* err); + + /** + * @brief Reads the Target property and stores in _tachTarget. + * Also calls Fan::tachChanged(). + * + * @param[in] msg - the dbus message + * @param[in] err - dbus error + */ + void handleTargetChange(sdbusplus::message::message& msg, + sd_bus_error* err); + + /** + * @brief Reads the Value property and stores in _tachInput. + * Also calls Fan::tachChanged(). + * + * @param[in] msg - the dbus message + * @param[in] err - dbus error + */ + void handleTachChange(sdbusplus::message::message& msg, + sd_bus_error* err); + + + /** * @brief the dbus object */ sdbusplus::bus::bus& _bus; @@ -139,6 +195,16 @@ class TachSensor * @brief The timeout value to use */ const size_t _timeout; + + /** + * @brief The match object for the Value properties changed signal + */ + std::unique_ptr<sdbusplus::server::match::match> tachSignal; + + /** + * @brief The match object for the Target properties changed signal + */ + std::unique_ptr<sdbusplus::server::match::match> targetSignal; }; } |