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