1 #pragma once
2 #include <memory>
3 #include "tach_sensor.hpp"
4 
5 namespace phosphor
6 {
7 namespace fan
8 {
9 namespace trust
10 {
11 
12 /**
13  * @class Group
14  *
15  * An abstract sensor trust group base class.
16  *
17  * Supports the ability to know if a fan speed sensor value can
18  * be trusted or not, where if it isn't trusted then it shouldn't
19  * be used to determine if the fan is faulted or not.
20  *
21  * It's a group in that there can be multiple sensors in the group
22  * and the trust of all sensors depends on something about those sensors.
23  * For example, if all sensors in the group report a speed of zero,
24  * then no sensor in the group is trusted.  All sensors in the group
25  * have the same trust value.
26  *
27  * Trust is calculated when checkTrust() is called after a group
28  * sensor's tach value changes.
29  *
30  * A derived class must override checkGroupTrust().
31  */
32 class Group
33 {
34     public:
35 
36         Group() = delete;
37         virtual ~Group() = default;
38         Group(const Group&) = delete;
39         Group& operator=(const Group&) = delete;
40         Group(Group&&) = default;
41         Group& operator=(Group&&) = default;
42 
43         /**
44          * Constructor
45          *
46          * @param[in] names - the names of the sensors in the group
47          */
48         explicit Group(const std::vector<std::string>& names) :
49                 _names(names)
50         {
51         }
52 
53         /**
54          * Used to register a TachSensor object with the group.
55          * It's only added to the group if the sensor's name is
56          * in the group's list of names.
57          *
58          * @param[in] sensor - the TachSensor to register
59          */
60         void registerSensor(std::unique_ptr<monitor::TachSensor>& sensor)
61         {
62             auto found = std::find_if(
63                     _names.begin(),
64                     _names.end(),
65                     [&sensor](const auto& name)
66                     {
67                         return monitor::FAN_SENSOR_PATH +
68                                 name == sensor->name();
69                     });
70 
71             if (found != _names.end())
72             {
73                 _sensors.push_back(sensor);
74             }
75         }
76 
77         /**
78          * Says if a sensor belongs to the group.
79          *
80          * After all sensors have registered, this can be
81          * used to say if a TachSensor is in the group.
82          *
83          * @param[in] sensor - the TachSensor object
84          */
85          bool inGroup(const monitor::TachSensor& sensor)
86          {
87              return (std::find_if(
88                      _sensors.begin(),
89                      _sensors.end(),
90                      [&sensor](const auto& s)
91                      {
92                          return sensor.name() == s.get()->name();
93                      }) != _sensors.end());
94          }
95 
96         /**
97          * Stops the timers on all sensors in the group.
98          *
99          * Called when the group just changed to not trusted,
100          * so that its sensors' timers can't fire a callback
101          * that may cause them to be considered faulted.
102          */
103         void stopTimers()
104         {
105             std::for_each(
106                     _sensors.begin(),
107                     _sensors.end(),
108                     [](const auto& s)
109                     {
110                         s.get()->stopTimer();
111                     });
112         }
113 
114         /**
115          * Starts the timers on all functional sensors in the group.
116          *
117          * Called when the group just changed to trusted.
118          */
119         void startTimers()
120         {
121             std::for_each(
122                     _sensors.begin(),
123                     _sensors.end(),
124                     [](const auto& s)
125                     {
126                         //If a sensor isn't functional, then its timer
127                         //already expired so don't bother starting it again
128                         if (s.get()->functional())
129                         {
130                             s.get()->startTimer();
131                         }
132                     });
133         }
134 
135         /**
136          * Determines the trust for this group based on this
137          * sensor's latest status.
138          *
139          * Calls the derived class's checkGroupTrust function
140          * and updates the class with the results.
141          *
142          * If this is called with a sensor not in the group,
143          * it will be considered trusted.
144          *
145          * @param[in] sensor - TachSensor object
146          *
147          * @return tuple<bool, bool> -
148          *   field 0 - the trust value
149          *   field 1 - if that trust value changed since last call
150          *             to checkTrust
151          */
152         auto checkTrust(const monitor::TachSensor& sensor)
153         {
154             if (inGroup(sensor))
155             {
156                 auto trust = checkGroupTrust();
157 
158                 setTrust(trust);
159 
160                 return std::tuple<bool, bool>(_trusted, _stateChange);
161             }
162             return std::tuple<bool, bool>(true, false);
163         }
164 
165         /**
166          * Says if all sensors in the group are currently trusted,
167          * as determined by the last call to checkTrust().
168          *
169          * @return bool - if the group's sensors are trusted or not
170          */
171         inline auto getTrust() const
172         {
173             return _trusted;
174         }
175 
176         /**
177          * Says if the trust value changed in the last call to
178          * checkTrust()
179          *
180          * @return bool - if the trust changed or not
181          */
182         inline auto trustChanged() const
183         {
184             return _stateChange;
185         }
186 
187     protected:
188 
189         /**
190          * The sensor objects in the group.
191          *
192          * Added by registerSensor().
193          */
194         std::vector<std::reference_wrapper<
195                 std::unique_ptr<monitor::TachSensor>>> _sensors;
196 
197     private:
198 
199         /**
200          * Checks if the group's sensors are trusted.
201          *
202          * The derived class must override this function
203          * to provide custom functionality.
204          *
205          * @return bool - if group is trusted or not
206          */
207         virtual bool checkGroupTrust() = 0;
208 
209         /**
210          * Sets the trust value on the object.
211          *
212          * @param[in] trust - the new trust value
213          */
214         inline void setTrust(bool trust)
215         {
216             _stateChange = (trust != _trusted);
217             _trusted = trust;
218         }
219 
220         /**
221          * The current trust state of the group
222          */
223         bool _trusted = true;
224 
225         /**
226          * If the trust value changed in the last call to checkTrust
227          */
228         bool _stateChange = false;
229 
230         /**
231          * The names of the sensors that should be added to this group
232          */
233         const std::vector<std::string> _names;
234 };
235 
236 }
237 }
238 }
239