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 phosphor::fan::monitor::TimerMode::nonfunc); 147 } 148 }); 149 } 150 151 /** 152 * Determines the trust for this group based on this 153 * sensor's latest status. 154 * 155 * Calls the derived class's checkGroupTrust function 156 * and updates the class with the results. 157 * 158 * If this is called with a sensor not in the group, 159 * it will be considered trusted. 160 * 161 * @param[in] sensor - TachSensor object 162 * 163 * @return tuple<bool, bool> - 164 * field 0 - the trust value 165 * field 1 - if that trust value changed since last call 166 * to checkTrust 167 */ 168 auto checkTrust(const monitor::TachSensor& sensor) 169 { 170 if (inGroup(sensor)) 171 { 172 auto trust = checkGroupTrust(); 173 174 setTrust(trust); 175 176 return std::tuple<bool, bool>(_trusted, _stateChange); 177 } 178 return std::tuple<bool, bool>(true, false); 179 } 180 181 /** 182 * Says if all sensors in the group are currently trusted, 183 * as determined by the last call to checkTrust(). 184 * 185 * @return bool - if the group's sensors are trusted or not 186 */ 187 inline auto getTrust() const 188 { 189 return _trusted; 190 } 191 192 /** 193 * Says if the trust value changed in the last call to 194 * checkTrust() 195 * 196 * @return bool - if the trust changed or not 197 */ 198 inline auto trustChanged() const 199 { 200 return _stateChange; 201 } 202 203 protected: 204 205 /** 206 * The sensor objects and their trust inclusion in the group. 207 * 208 * Added by registerSensor(). 209 */ 210 std::vector<GroupSensor> _sensors; 211 212 private: 213 214 /** 215 * Checks if the group's sensors are trusted. 216 * 217 * The derived class must override this function 218 * to provide custom functionality. 219 * 220 * @return bool - if group is trusted or not 221 */ 222 virtual bool checkGroupTrust() = 0; 223 224 /** 225 * Sets the trust value on the object. 226 * 227 * @param[in] trust - the new trust value 228 */ 229 inline void setTrust(bool trust) 230 { 231 _stateChange = (trust != _trusted); 232 _trusted = trust; 233 } 234 235 /** 236 * The current trust state of the group 237 */ 238 bool _trusted = true; 239 240 /** 241 * If the trust value changed in the last call to checkTrust 242 */ 243 bool _stateChange = false; 244 245 /** 246 * The names of the sensors and whether it is included in 247 * determining trust for this group 248 */ 249 const std::vector<GroupDefinition> _names; 250 }; 251 252 } 253 } 254 } 255