blob: 5892ba247048ac49a8e9752e7d07a98048ef1a05 [file] [log] [blame] [edit]
#pragma once
#include "config.h"
#include "tach_sensor.hpp"
#include "trust_manager.hpp"
#include "types.hpp"
#include <sdbusplus/bus.hpp>
#include <sdeventplus/event.hpp>
#include <tuple>
#include <vector>
namespace phosphor
{
namespace fan
{
namespace monitor
{
class System;
/**
* @class Fan
*
* Represents a fan, which can contain 1 or more sensors which
* loosely correspond to rotors. See below.
*
* There is a sensor when hwmon exposes one, which means there is a
* speed value to be read. Sometimes there is a sensor per rotor,
* and other times multiple rotors just use 1 sensor total where
* the sensor reports the slowest speed of all of the rotors.
*
* A rotor's speed is set by writing the Target value of a sensor.
* Sometimes each sensor in a fan supports having a Target, and other
* times not all of them do. A TachSensor object knows if it supports
* the Target property.
*
* The strategy for monitoring fan speeds is as follows:
*
* Every time a Target (new speed written) or Input (actual speed read)
* sensor changes, check if the input value is within some range of the target
* value. If it isn't, start a timer at the end of which the sensor will be
* set to not functional. If enough sensors in the fan are now nonfunctional,
* set the whole fan to nonfunctional in the inventory.
*
* When sensor inputs come back within a specified range of the target,
* stop its timer if running, make the sensor functional again if it wasn't,
* and if enough sensors in the fan are now functional set the whole fan
* back to functional in the inventory.
*/
class Fan
{
using Property = std::string;
using Value = std::variant<bool>;
using PropertyMap = std::map<Property, Value>;
using Interface = std::string;
using InterfaceMap = std::map<Interface, PropertyMap>;
using Object = sdbusplus::message::object_path;
using ObjectMap = std::map<Object, InterfaceMap>;
public:
Fan() = delete;
Fan(const Fan&) = delete;
Fan(Fan&&) = default;
Fan& operator=(const Fan&) = delete;
Fan& operator=(Fan&&) = default;
~Fan() = default;
/**
* @brief Constructor
*
* @param mode - mode of fan monitor
* @param bus - the dbus object
* @param event - event loop reference
* @param trust - the tach trust manager
* @param def - the fan definition structure
* @param system - Reference to the system object
*/
Fan(Mode mode, sdbusplus::bus_t& bus, const sdeventplus::Event& event,
std::unique_ptr<trust::Manager>& trust, const FanDefinition& def,
System& system);
/**
* @brief Callback function for when an input sensor changes
*
* Starts a timer, where if it expires then the sensor
* was out of range for too long and can be considered not functional.
*/
void tachChanged(TachSensor& sensor);
/**
* @brief Calls tachChanged(sensor) on each sensor
*/
void tachChanged();
/**
* @brief The callback function for the method
*
* Sets the sensor to not functional.
* If enough sensors are now not functional,
* updates the functional status of the whole
* fan in the inventory.
*
* @param[in] sensor - the sensor for state update
*/
void updateState(TachSensor& sensor);
/**
* @brief Get the name of the fan
*
* @return - The fan name
*/
inline const std::string& getName() const
{
return _name;
}
/**
* @brief Finds the target speed of this fan
*
* Finds the target speed from the list of sensors that make up this
* fan. At least one sensor should contain a target speed value.
*
* @return - The target speed found from the list of sensors on the fan
*/
uint64_t findTargetSpeed();
/**
* @brief Returns the contained TachSensor objects
*
* @return std::vector<std::shared_ptr<TachSensor>> - The sensors
*/
const std::vector<std::shared_ptr<TachSensor>>& sensors() const
{
return _sensors;
}
/**
* @brief Returns the presence status of the fan
*
* @return bool - If the fan is present or not
*/
bool present() const
{
return _present;
}
/**
* @brief Called from TachSensor when its error timer expires
* so an event log calling out the fan can be created.
*
* @param[in] sensor - The nonfunctional sensor
*/
void sensorErrorTimerExpired(const TachSensor& sensor);
/**
* @brief Process the state of the given tach sensor without checking
* any trust groups the sensor may be included in
*
* @param[in] sensor - Tach sensor to process
*
* This function is intended to check the current state of a tach sensor
* regardless of whether or not the tach sensor is configured to be in any
* trust groups.
*/
void process(TachSensor& sensor);
/**
* @brief The function that runs when the power state changes
*
* @param[in] powerStateOn - If power is now on or not
*/
void powerStateChanged(bool powerStateOn);
/**
* @brief Timer callback function that deals with sensors using
* the 'count' method for determining functional status.
*
* @param[in] sensor - TachSensor object
*/
void countTimerExpired(TachSensor& sensor);
/**
* @brief Returns the number of tach sensors (Sensor.Value ifaces)
* on D-Bus at the last power on.
*/
inline size_t numSensorsOnDBusAtPowerOn() const
{
return _numSensorsOnDBusAtPowerOn;
}
/**
* @brief Returns true if the sensor input is not within
* some deviation of the target.
*
* @param[in] sensor - the sensor to check
*/
bool outOfRange(const TachSensor& sensor);
private:
/**
* @brief Returns the number sensors that are nonfunctional
*/
size_t countNonFunctionalSensors() const;
/**
* @brief Updates the Functional property in the inventory
* for the fan based on the value passed in.
*
* @param[in] functional - If the Functional property should
* be set to true or false.
*
* @return - True if an exception was encountered during update
*/
bool updateInventory(bool functional);
/**
* @brief Called by _monitorTimer to start fan monitoring some
* amount of time after startup.
*/
void startMonitor();
/**
* @brief Called when the fan presence property changes on D-Bus
*
* @param[in] msg - The message from the propertiesChanged signal
*/
void presenceChanged(sdbusplus::message_t& msg);
/**
* @brief Called when there is an interfacesAdded signal on the
* fan D-Bus path so the code can look for the 'Present'
* property value.
*
* @param[in] msg - The message from the interfacesAdded signal
*/
void presenceIfaceAdded(sdbusplus::message_t& msg);
/**
* @brief the dbus object
*/
sdbusplus::bus_t& _bus;
/**
* @brief The inventory name of the fan
*/
const std::string _name;
/**
* @brief The percentage that the input speed must be below
* the target speed to be considered an error.
* Between 0 and 100.
*/
const size_t _deviation;
/**
* @brief The percentage that the input speed must be above
* the target speed to be considered an error.
* Between 0 and 100.
*/
const size_t _upperDeviation;
/**
* The number of sensors that must be nonfunctional at the
* same time in order for the fan to be set to nonfunctional
* in the inventory.
*/
const size_t _numSensorFailsForNonFunc;
/**
* The number of failed sensors
*/
size_t _numFailedSensor = 0;
/**
* @brief The current functional state of the fan
*/
bool _functional = true;
/**
* The sensor objects for the fan
*/
std::vector<std::shared_ptr<TachSensor>> _sensors;
/**
* The tach trust manager object
*/
std::unique_ptr<trust::Manager>& _trustManager;
#ifdef MONITOR_USE_JSON
/**
* @brief The number of seconds to wait after startup until
* fan sensors should checked against their targets.
*/
size_t _monitorDelay;
/**
* @brief Expires after _monitorDelay to start fan monitoring.
*/
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _monitorTimer;
#endif
/**
* @brief Set to true when monitoring can start.
*/
bool _monitorReady = false;
/**
* @brief Reference to the System object
*/
System& _system;
/**
* @brief The match object for propertiesChanged signals
* for the inventory item interface to track the
* Present property.
*/
sdbusplus::bus::match_t _presenceMatch;
/**
* @brief The match object for the interfacesAdded signal
* for the interface that has the Present property.
*/
sdbusplus::bus::match_t _presenceIfaceAddedMatch;
/**
* @brief The current presence state
*/
bool _present = false;
/**
* @brief The number of seconds to wait after a fan is removed before
* creating an event log for it. If std::nullopt, then no
* event log will be created.
*/
const std::optional<size_t> _fanMissingErrorDelay;
/**
* @brief The timer that uses the _fanMissingErrorDelay timeout,
* at the end of which an event log will be created.
*/
std::unique_ptr<
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
_fanMissingErrorTimer;
/**
* @brief If the fan and sensors should be set to functional when
* a fan plug is detected.
*/
bool _setFuncOnPresent;
/**
* @brief The number of sensors that have their Sensor.Value interfaces
* on D-Bus at the last power on.
*
* Will be zero until the power turns on the first time.
*/
size_t _numSensorsOnDBusAtPowerOn = 0;
};
} // namespace monitor
} // namespace fan
} // namespace phosphor