xref: /openbmc/phosphor-fan-presence/monitor/trust_group.hpp (revision 8e5d197b840d4498dcb714b60cc1d38202a7a7a7)
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 if
116          * their target and input values do not match.
117          *
118          * Called when the group just changed to trusted.
119          */
120         void startTimers()
121         {
122             std::for_each(
123                     _sensors.begin(),
124                     _sensors.end(),
125                     [](const auto& s)
126                     {
127                         //If a sensor isn't functional, then its timer
128                         //already expired so don't bother starting it again
129                         if (s.get()->functional() &&
130                             static_cast<uint64_t>(s.get()->getInput()) !=
131                                     s.get()->getTarget())
132                         {
133                             s.get()->startTimer();
134                         }
135                     });
136         }
137 
138         /**
139          * Determines the trust for this group based on this
140          * sensor's latest status.
141          *
142          * Calls the derived class's checkGroupTrust function
143          * and updates the class with the results.
144          *
145          * If this is called with a sensor not in the group,
146          * it will be considered trusted.
147          *
148          * @param[in] sensor - TachSensor object
149          *
150          * @return tuple<bool, bool> -
151          *   field 0 - the trust value
152          *   field 1 - if that trust value changed since last call
153          *             to checkTrust
154          */
155         auto checkTrust(const monitor::TachSensor& sensor)
156         {
157             if (inGroup(sensor))
158             {
159                 auto trust = checkGroupTrust();
160 
161                 setTrust(trust);
162 
163                 return std::tuple<bool, bool>(_trusted, _stateChange);
164             }
165             return std::tuple<bool, bool>(true, false);
166         }
167 
168         /**
169          * Says if all sensors in the group are currently trusted,
170          * as determined by the last call to checkTrust().
171          *
172          * @return bool - if the group's sensors are trusted or not
173          */
174         inline auto getTrust() const
175         {
176             return _trusted;
177         }
178 
179         /**
180          * Says if the trust value changed in the last call to
181          * checkTrust()
182          *
183          * @return bool - if the trust changed or not
184          */
185         inline auto trustChanged() const
186         {
187             return _stateChange;
188         }
189 
190     protected:
191 
192         /**
193          * The sensor objects in the group.
194          *
195          * Added by registerSensor().
196          */
197         std::vector<std::reference_wrapper<
198                 std::unique_ptr<monitor::TachSensor>>> _sensors;
199 
200     private:
201 
202         /**
203          * Checks if the group's sensors are trusted.
204          *
205          * The derived class must override this function
206          * to provide custom functionality.
207          *
208          * @return bool - if group is trusted or not
209          */
210         virtual bool checkGroupTrust() = 0;
211 
212         /**
213          * Sets the trust value on the object.
214          *
215          * @param[in] trust - the new trust value
216          */
217         inline void setTrust(bool trust)
218         {
219             _stateChange = (trust != _trusted);
220             _trusted = trust;
221         }
222 
223         /**
224          * The current trust state of the group
225          */
226         bool _trusted = true;
227 
228         /**
229          * If the trust value changed in the last call to checkTrust
230          */
231         bool _stateChange = false;
232 
233         /**
234          * The names of the sensors that should be added to this group
235          */
236         const std::vector<std::string> _names;
237 };
238 
239 }
240 }
241 }
242