1 #pragma once
2 
3 #include <sdbusplus/bus.hpp>
4 #include <tuple>
5 #include <vector>
6 #include "event.hpp"
7 #include "tach_sensor.hpp"
8 #include "types.hpp"
9 
10 namespace phosphor
11 {
12 namespace fan
13 {
14 namespace monitor
15 {
16 
17 
18 /**
19  * @class Fan
20  *
21  * Represents a fan, which can contain 1 or more sensors which
22  * loosely correspond to rotors.  See below.
23  *
24  * There is a sensor when hwmon exposes one, which means there is a
25  * speed value to be read.  Sometimes there is a sensor per rotor,
26  * and other times multiple rotors just use 1 sensor total where
27  * the sensor reports the slowest speed of all of the rotors.
28  *
29  * A rotor's speed is set by writing the Target value of a sensor.
30  * Sometimes each sensor in a fan supports having a Target, and other
31  * times not all of them do.  A TachSensor object knows if it supports
32  * the Target property.
33  *
34  * The strategy for monitoring fan speeds is as follows:
35  *
36  * Every time a Target (new speed written) or Input (actual speed read)
37  * sensor changes, check if the input value is within some range of the target
38  * value.  If it isn't, start a timer at the end of which the sensor will be
39  * set to not functional.  If enough sensors in the fan are now nonfunctional,
40  * set the whole fan to nonfunctional in the inventory.
41  *
42  * When sensor inputs come back within a specified range of the target,
43  * stop its timer if running, make the sensor functional again if it wasn't,
44  * and if enough sensors in the fan are now functional set the whole fan
45  * back to functional in the inventory.
46  */
47 class Fan
48 {
49     using Property = std::string;
50     using Value = sdbusplus::message::variant<bool>;
51     using PropertyMap = std::map<Property, Value>;
52 
53     using Interface = std::string;
54     using InterfaceMap = std::map<Interface, PropertyMap>;
55 
56     using Object = sdbusplus::message::object_path;
57     using ObjectMap = std::map<Object, InterfaceMap>;
58 
59     public:
60 
61         Fan() = delete;
62         Fan(const Fan&) = delete;
63         Fan(Fan&&) = default;
64         Fan& operator=(const Fan&) = delete;
65         Fan& operator=(Fan&&) = default;
66         ~Fan() = default;
67 
68         /**
69          * @brief Constructor
70          *
71          * @param bus - the dbus object
72          * @param events - pointer to sd_event object
73          * @param def - the fan definition structure
74          */
75         Fan(sdbusplus::bus::bus& bus,
76             phosphor::fan::event::EventPtr& events,
77             const FanDefinition& def);
78 
79         /**
80          * @brief Callback function for when an input sensor changes
81          *
82          * Starts a timer, where if it expires then the sensor
83          * was out of range for too long and can be considered not functional.
84          */
85         void tachChanged(TachSensor& sensor);
86 
87         /**
88          * @brief Calls tachChanged(sensor) on each sensor
89          */
90         void tachChanged();
91 
92         /**
93          * @brief The callback function for the timer
94          *
95          * Sets the sensor to not functional.
96          * If enough sensors are now not functional,
97          * updates the functional status of the whole
98          * fan in the inventory.
99          *
100          * @param[in] sensor - the sensor whose timer expired
101          */
102         void timerExpired(TachSensor& sensor);
103 
104     private:
105 
106         /**
107          * @brief Returns the target speed of the sensor
108          *
109          * If the sensor itself doesn't have a target, it finds
110          * the target speed from another sensor.
111          *
112          * @param[in] sensor - the sensor to get the target speed for
113          */
114         uint64_t getTargetSpeed(const TachSensor& sensor);
115 
116         /**
117          * @brief Returns true if the sensor input is not within
118          * some deviation of the target.
119          *
120          * @param[in] sensor - the sensor to check
121          */
122         bool outOfRange(const TachSensor& sensor);
123 
124         /**
125          * @brief Returns true if too many sensors are nonfunctional
126          *        as defined by _numSensorFailsForNonFunc
127          */
128         bool tooManySensorsNonfunctional();
129 
130         /**
131          * @brief Updates the Functional property in the inventory
132          *        for the fan based on the value passed in.
133          *
134          * @param[in] functional - If the Functional property should
135          *                         be set to true or false.
136          */
137         void updateInventory(bool functional);
138 
139         /**
140          * @brief Returns the object map to use when updating the inventory
141          *
142          * @param[in] functional - If the Functional property should
143          *                         be set to true or false.
144          */
145         ObjectMap getObjectMap(bool functional);
146 
147         /**
148          * @brief the dbus object
149          */
150         sdbusplus::bus::bus& _bus;
151 
152         /**
153          * @brief The inventory name of the fan
154          */
155         const std::string _name;
156 
157         /**
158          * @brief The percentage that the input speed must be below
159          *        the target speed to be considered an error.
160          *        Between 0 and 100.
161          */
162         const size_t _deviation;
163 
164         /**
165          * The number of sensors that must be nonfunctional at the
166          * same time in order for the fan to be set to nonfunctional
167          * in the inventory.
168          */
169         const size_t _numSensorFailsForNonFunc;
170 
171         /**
172          * @brief The current functional state of the fan
173          */
174         bool _functional = true;
175 
176         /**
177          * The sensor objects for the fan
178          */
179         std::vector<std::unique_ptr<TachSensor>> _sensors;
180 };
181 
182 }
183 }
184 }
185