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