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