1 #pragma once 2 3 #include "dbusSensor.hpp" 4 #include "exprtkTools.hpp" 5 #include "thresholds.hpp" 6 7 #include <nlohmann/json.hpp> 8 #include <phosphor-logging/lg2.hpp> 9 #include <sdbusplus/bus.hpp> 10 #include <xyz/openbmc_project/Association/Definitions/server.hpp> 11 #include <xyz/openbmc_project/Sensor/Value/server.hpp> 12 13 #include <map> 14 #include <string> 15 16 namespace phosphor::virtual_sensor 17 { 18 19 PHOSPHOR_LOG2_USING_WITH_FLAGS; 20 21 using BasicVariantType = 22 std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t, 23 int16_t, uint16_t, uint8_t, bool, std::vector<std::string>>; 24 25 using PropertyMap = std::map<std::string, BasicVariantType>; 26 27 using InterfaceMap = std::map<std::string, PropertyMap>; 28 29 using ManagedObjectType = 30 std::map<sdbusplus::message::object_path, InterfaceMap>; 31 32 using Json = nlohmann::json; 33 34 template <typename... T> 35 using ServerObject = typename sdbusplus::server::object_t<T...>; 36 37 using ValueIface = sdbusplus::xyz::openbmc_project::Sensor::server::Value; 38 using ValueObject = ServerObject<ValueIface>; 39 40 using AssociationIface = 41 sdbusplus::xyz::openbmc_project::Association::server::Definitions; 42 using AssociationObject = ServerObject<AssociationIface>; 43 44 class SensorParam 45 { 46 public: 47 SensorParam() = delete; 48 virtual ~SensorParam() = default; 49 50 enum ParamType 51 { 52 constParam, 53 dbusParam 54 }; 55 56 /** @brief Constructs SensorParam (type = constParam) 57 * 58 * @param[in] value - Value of constant parameter 59 */ SensorParam(double value)60 explicit SensorParam(double value) : value(value), paramType(constParam) {} 61 62 /** @brief Constructs SensorParam (type = dbusParam) 63 * 64 * @param[in] bus - Handle to system dbus 65 * @param[in] path - The Dbus path of sensor 66 * @param[in] ctx - sensor context for update 67 */ SensorParam(sdbusplus::bus_t & bus,const std::string & path,VirtualSensor & ctx)68 SensorParam(sdbusplus::bus_t& bus, const std::string& path, 69 VirtualSensor& ctx) : 70 dbusSensor(std::make_unique<DbusSensor>(bus, path, ctx)), 71 paramType(dbusParam) 72 {} 73 74 /** @brief Get sensor value property from D-bus interface */ 75 double getParamValue(); 76 77 private: 78 std::unique_ptr<DbusSensor> dbusSensor = nullptr; 79 80 /** @brief virtual sensor value */ 81 double value = std::numeric_limits<double>::quiet_NaN(); 82 ParamType paramType; 83 }; 84 85 class VirtualSensor : public ValueObject 86 { 87 public: 88 VirtualSensor() = delete; 89 virtual ~VirtualSensor() = default; 90 91 /** @brief Constructs VirtualSensor 92 * 93 * @param[in] bus - Handle to system dbus 94 * @param[in] objPath - The Dbus path of sensor 95 * @param[in] sensorConfig - Json object for sensor config 96 * @param[in] name - Sensor name 97 * @param[in] type - sensor type/unit 98 */ VirtualSensor(sdbusplus::bus_t & bus,const char * objPath,const Json & sensorConfig,const std::string & name,const std::string & type)99 VirtualSensor(sdbusplus::bus_t& bus, const char* objPath, 100 const Json& sensorConfig, const std::string& name, 101 const std::string& type) : 102 ValueObject(bus, objPath, action::defer_emit), bus(bus), name(name), 103 objPath(objPath) 104 { 105 initVirtualSensor(sensorConfig, objPath, type); 106 } 107 108 /** @brief Constructs VirtualSensor 109 * 110 * @param[in] bus - Handle to system dbus 111 * @param[in] objPath - The Dbus path of sensor 112 * @param[in] ifacemap - All the sensor information 113 * @param[in] name - Virtual sensor name 114 * @param[in] type - Virtual sensor type/unit 115 * @param[in] calcType - Calculation used to calculate sensor value 116 * @param[in] entityPath - Virtual sensor path in entityManager Dbus 117 * 118 */ VirtualSensor(sdbusplus::bus_t & bus,const char * objPath,const InterfaceMap & ifacemap,const std::string & name,const std::string & type,const std::string & calculationType,const std::string & entityPath)119 VirtualSensor(sdbusplus::bus_t& bus, const char* objPath, 120 const InterfaceMap& ifacemap, const std::string& name, 121 const std::string& type, const std::string& calculationType, 122 const std::string& entityPath) : 123 ValueObject(bus, objPath, action::defer_emit), bus(bus), name(name), 124 objPath(objPath), entityPath(entityPath) 125 { 126 initVirtualSensor(ifacemap, objPath, type, calculationType); 127 } 128 129 /** @brief Set sensor value */ 130 void setSensorValue(double value); 131 132 /** @brief Update sensor at regular intrval */ 133 void updateVirtualSensor(); 134 135 /** @brief Check if sensor value is in valid range */ 136 bool sensorInRange(double value); 137 138 /** @brief Map of list of parameters */ 139 using ParamMap = 140 std::unordered_map<std::string, std::unique_ptr<SensorParam>>; 141 ParamMap paramMap; 142 143 private: 144 /** @brief sdbusplus bus client connection. */ 145 sdbusplus::bus_t& bus; 146 /** @brief name of sensor */ 147 std::string name; 148 /** @brief unit of sensor */ 149 ValueIface::Unit units; 150 /** @brief object path of this sensor */ 151 std::string objPath; 152 153 /** @brief Virtual sensor path in entityManager Dbus. 154 * This value is used to set thresholds/create association 155 */ 156 std::string entityPath; 157 /** @brief Expression string for virtual sensor value calculations */ 158 std::string exprStr; 159 /** @brief symbol table from exprtk */ 160 exprtk::symbol_table<double> symbols{}; 161 /** @brief expression from exprtk to calculate sensor value */ 162 exprtk::expression<double> expression{}; 163 /** @brief The vecops package so the expression can use vectors */ 164 exprtk::rtl::vecops::package<double> vecopsPackage; 165 /** @brief The maximum valid value for an input sensor **/ 166 double maxValidInput = std::numeric_limits<double>::infinity(); 167 /** @brief The minimum valid value for an input sensor **/ 168 double minValidInput = -std::numeric_limits<double>::infinity(); 169 170 /** @brief The critical threshold interface object */ 171 std::unique_ptr<Threshold<CriticalObject>> criticalIface; 172 /** @brief The warning threshold interface object */ 173 std::unique_ptr<Threshold<WarningObject>> warningIface; 174 /** @brief The soft shutdown threshold interface object */ 175 std::unique_ptr<Threshold<SoftShutdownObject>> softShutdownIface; 176 /** @brief The hard shutdown threshold interface object */ 177 std::unique_ptr<Threshold<HardShutdownObject>> hardShutdownIface; 178 /** @brief The performance loss threshold interface object */ 179 std::unique_ptr<Threshold<PerformanceLossObject>> perfLossIface; 180 181 /** @brief The association interface object */ 182 std::unique_ptr<AssociationObject> associationIface; 183 184 static FuncMaxIgnoreNaN<double> funcMaxIgnoreNaN; 185 static FuncSumIgnoreNaN<double> funcSumIgnoreNaN; 186 static FuncIfNan<double> funcIfNan; 187 188 /** @brief Read config from json object and initialize sensor data 189 * for each virtual sensor 190 */ 191 void initVirtualSensor(const Json& sensorConfig, const std::string& objPath, 192 const std::string& type); 193 194 /** @brief Read config from interface map and initialize sensor data 195 * for each virtual sensor 196 */ 197 void initVirtualSensor(const InterfaceMap& interfaceMap, 198 const std::string& objPath, 199 const std::string& sensorType, 200 const std::string& calculationType); 201 202 /** @brief Returns which calculation function or expression to use */ 203 double calculateValue(const std::string& sensortype, 204 const VirtualSensor::ParamMap& paramMap); 205 /** @brief create threshold objects from json config */ 206 void createThresholds(const Json& threshold, const std::string& objPath, 207 ValueIface::Unit units); 208 /** @brief parse config from entity manager **/ 209 void parseConfigInterface(const PropertyMap& propertyMap, 210 const std::string& sensorType, 211 const std::string& interface); 212 213 /** @brief Check Sensor threshold and update alarm and log. Returns 214 * true if the threshold range has no alarms set. change will be 215 * set if a change to the alarms were detected, else will be left 216 * unchanged */ 217 template <typename V, typename T> checkThresholds(V value,T & threshold,bool & change)218 bool checkThresholds(V value, T& threshold, bool& change) 219 { 220 if (!threshold) 221 return true; 222 223 static constexpr auto tname = T::element_type::name; 224 225 auto alarmHigh = threshold->alarmHigh(); 226 auto highHysteresis = threshold->getHighHysteresis(); 227 if ((!alarmHigh && value >= threshold->high()) || 228 (alarmHigh && value < (threshold->high() - highHysteresis))) 229 { 230 change = true; 231 if (!alarmHigh) 232 { 233 error("ASSERT: sensor {SENSOR} is above the upper threshold " 234 "{THRESHOLD}.", 235 "SENSOR", name, "THRESHOLD", tname); 236 threshold->alarmHighSignalAsserted(value); 237 } 238 else 239 { 240 info("DEASSERT: sensor {SENSOR} is under the upper threshold " 241 "{THRESHOLD}.", 242 "SENSOR", name, "THRESHOLD", tname); 243 threshold->alarmHighSignalDeasserted(value); 244 } 245 alarmHigh = !alarmHigh; 246 threshold->alarmHigh(alarmHigh); 247 } 248 249 auto alarmLow = threshold->alarmLow(); 250 auto lowHysteresis = threshold->getLowHysteresis(); 251 if ((!alarmLow && value <= threshold->low()) || 252 (alarmLow && value > (threshold->low() + lowHysteresis))) 253 { 254 change = true; 255 if (!alarmLow) 256 { 257 error("ASSERT: sensor {SENSOR} is below the lower threshold " 258 "{THRESHOLD}.", 259 "SENSOR", name, "THRESHOLD", tname); 260 threshold->alarmLowSignalAsserted(value); 261 } 262 else 263 { 264 info("DEASSERT: sensor {SENSOR} is above the lower threshold " 265 "{THRESHOLD}.", 266 "SENSOR", name, "THRESHOLD", tname); 267 threshold->alarmLowSignalDeasserted(value); 268 } 269 alarmLow = !alarmLow; 270 threshold->alarmLow(alarmLow); 271 } 272 return !alarmHigh && !alarmLow; 273 } 274 275 /** @brief Create Association from entityPath*/ 276 void createAssociation(const std::string& objPath, 277 const std::string& entityPath); 278 }; 279 280 class VirtualSensors 281 { 282 public: 283 VirtualSensors() = delete; 284 virtual ~VirtualSensors() = default; 285 286 /** @brief Constructs VirtualSensors 287 * 288 * @param[in] bus - Handle to system dbus 289 */ VirtualSensors(sdbusplus::bus_t & bus)290 explicit VirtualSensors(sdbusplus::bus_t& bus) : bus(bus) 291 { 292 createVirtualSensors(); 293 } 294 /** @brief Calls createVirtualSensor when interface added */ 295 void propertiesChanged(sdbusplus::message_t& msg); 296 297 private: 298 /** @brief sdbusplus bus client connection. */ 299 sdbusplus::bus_t& bus; 300 /** @brief Get virtual sensor config from DBus**/ 301 ManagedObjectType getObjectsFromDBus(); 302 /** @brief Parsing virtual sensor config JSON file */ 303 Json parseConfigFile(); 304 305 /** @brief Matches for virtual sensors */ 306 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches; 307 /** @brief Map of the object VirtualSensor */ 308 std::unordered_map<std::string, std::unique_ptr<VirtualSensor>> 309 virtualSensorsMap; 310 311 /** @brief Create list of virtual sensors from JSON config*/ 312 void createVirtualSensors(); 313 /** @brief Create list of virtual sensors from DBus config */ 314 void createVirtualSensorsFromDBus(const std::string& calculationType); 315 /** @brief Setup matches for virtual sensors */ 316 void setupMatches(); 317 }; 318 319 } // namespace phosphor::virtual_sensor 320