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      * Used to register a TachSensor object with the group.
62      * It's only added to the group if the sensor's name is
63      * in the group's list of names.
64      *
65      * @param[in] sensor - the TachSensor to register
66      */
67     void registerSensor(std::shared_ptr<monitor::TachSensor>& sensor)
68     {
69         auto found = std::find_if(_names.begin(), _names.end(),
70                                   [&sensor](const auto& name) {
71             return monitor::FAN_SENSOR_PATH + std::get<sensorName>(name) ==
72                    sensor->name();
73         });
74 
75         if (found != _names.end())
76         {
77             _sensors.push_back({sensor, std::get<inTrust>(*found)});
78         }
79     }
80 
81     /**
82      * Says if a sensor belongs to the group.
83      *
84      * After all sensors have registered, this can be
85      * used to say if a TachSensor is in the group.
86      *
87      * @param[in] sensor - the TachSensor object
88      */
89     bool inGroup(const monitor::TachSensor& sensor)
90     {
91         return (std::find_if(_sensors.begin(), _sensors.end(),
92                              [&sensor](const auto& s) {
93             return sensor.name() == s.sensor->name();
94                 }) != _sensors.end());
95     }
96 
97     /**
98      * Cancels monitoring on all sensors in the group.
99      *
100      * Called when the group just changed to not trusted,
101      * so that its sensors' monitoring method does not
102      * cause them to be considered faulted.
103      */
104     void cancelMonitoring()
105     {
106         std::for_each(_sensors.begin(), _sensors.end(),
107                       [](const auto& s) { s.sensor->resetMethod(); });
108     }
109 
110     /**
111      * Starts monitoring on all sensors in the group by processing their current
112      * state
113      *
114      * Called when the group just changed to trusted.
115      */
116     void startMonitoring()
117     {
118         std::for_each(_sensors.begin(), _sensors.end(),
119                       [](const auto& s) { s.sensor->processState(); });
120     }
121 
122     /**
123      * Determines the trust for this group based on this
124      * sensor's latest status.
125      *
126      * Calls the derived class's checkGroupTrust function
127      * and updates the class with the results.
128      *
129      * If this is called with a sensor not in the group,
130      * it will be considered trusted.
131      *
132      * @param[in] sensor - TachSensor object
133      *
134      * @return tuple<bool, bool> -
135      *   field 0 - the trust value
136      *   field 1 - if that trust value changed since last call
137      *             to checkTrust
138      */
139     auto checkTrust(const monitor::TachSensor& sensor)
140     {
141         if (inGroup(sensor))
142         {
143             auto trust = checkGroupTrust();
144 
145             setTrust(trust);
146 
147             return std::tuple<bool, bool>(_trusted, _stateChange);
148         }
149         return std::tuple<bool, bool>(true, false);
150     }
151 
152     /**
153      * Says if all sensors in the group are currently trusted,
154      * as determined by the last call to checkTrust().
155      *
156      * @return bool - if the group's sensors are trusted or not
157      */
158     inline auto getTrust() const
159     {
160         return _trusted;
161     }
162 
163     /**
164      * Says if the trust value changed in the last call to
165      * checkTrust()
166      *
167      * @return bool - if the trust changed or not
168      */
169     inline auto trustChanged() const
170     {
171         return _stateChange;
172     }
173 
174   protected:
175     /**
176      * The sensor objects and their trust inclusion in the group.
177      *
178      * Added by registerSensor().
179      */
180     std::vector<GroupSensor> _sensors;
181 
182   private:
183     /**
184      * Checks if the group's sensors are trusted.
185      *
186      * The derived class must override this function
187      * to provide custom functionality.
188      *
189      * @return bool - if group is trusted or not
190      */
191     virtual bool checkGroupTrust() = 0;
192 
193     /**
194      * Sets the trust value on the object.
195      *
196      * @param[in] trust - the new trust value
197      */
198     inline void setTrust(bool trust)
199     {
200         _stateChange = (trust != _trusted);
201         _trusted = trust;
202     }
203 
204     /**
205      * The current trust state of the group
206      */
207     bool _trusted = true;
208 
209     /**
210      * If the trust value changed in the last call to checkTrust
211      */
212     bool _stateChange = false;
213 
214     /**
215      * The names of the sensors and whether it is included in
216      * determining trust for this group
217      */
218     const std::vector<GroupDefinition> _names;
219 }; // namespace trust
220 
221 } // namespace trust
222 } // namespace fan
223 } // namespace phosphor
224