blob: b4fd815795af2835ee809afcc3362c9d8ef7435e [file] [log] [blame]
Vijay Khemka7452a862020-08-11 16:01:23 -07001#include "dbusSensor.hpp"
Vijay Khemka92d648b2020-08-21 18:55:07 -07002#include "exprtkTools.hpp"
Matt Spinler8f5e6112021-01-15 10:44:32 -06003#include "thresholds.hpp"
4
5#include <fmt/format.h>
Vijay Khemka7452a862020-08-11 16:01:23 -07006
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07007#include <nlohmann/json.hpp>
8#include <sdbusplus/bus.hpp>
Lei YU0fcf0e12021-06-04 11:14:17 +08009#include <xyz/openbmc_project/Association/Definitions/server.hpp>
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070010#include <xyz/openbmc_project/Sensor/Value/server.hpp>
11
12#include <map>
13#include <string>
14
15namespace phosphor
16{
17namespace virtualSensor
18{
19
Rashmica Guptae7efe132021-07-27 19:42:11 +100020using BasicVariantType =
21 std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t,
22 int16_t, uint16_t, uint8_t, bool, std::vector<std::string>>;
23
24using PropertyMap = std::map<std::string, BasicVariantType>;
25
26using InterfaceMap = std::map<std::string, PropertyMap>;
27
28using ManagedObjectType =
29 std::map<sdbusplus::message::object_path, InterfaceMap>;
30
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070031using Json = nlohmann::json;
Matt Spinlerce675222021-01-14 16:38:09 -060032
33template <typename... T>
34using ServerObject = typename sdbusplus::server::object::object<T...>;
35
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070036using ValueIface = sdbusplus::xyz::openbmc_project::Sensor::server::Value;
Matt Spinlerce675222021-01-14 16:38:09 -060037using ValueObject = ServerObject<ValueIface>;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070038
Lei YU0fcf0e12021-06-04 11:14:17 +080039using AssociationIface =
40 sdbusplus::xyz::openbmc_project::Association::server::Definitions;
41using AssociationObject = ServerObject<AssociationIface>;
42
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070043class SensorParam
44{
45 public:
46 SensorParam() = delete;
47 virtual ~SensorParam() = default;
48
49 enum ParamType
50 {
51 constParam,
52 dbusParam
53 };
54
55 /** @brief Constructs SensorParam (type = constParam)
56 *
57 * @param[in] value - Value of constant parameter
58 */
59 explicit SensorParam(double value) : value(value), paramType(constParam)
60 {}
61
Vijay Khemka7452a862020-08-11 16:01:23 -070062 /** @brief Constructs SensorParam (type = dbusParam)
63 *
64 * @param[in] bus - Handle to system dbus
65 * @param[in] path - The Dbus path of sensor
Vijay Khemka51f898e2020-09-09 22:24:18 -070066 * @param[in] ctx - sensor context for update
Vijay Khemka7452a862020-08-11 16:01:23 -070067 */
Vijay Khemka51f898e2020-09-09 22:24:18 -070068 SensorParam(sdbusplus::bus::bus& bus, std::string path, void* ctx) :
69 dbusSensor(std::make_unique<DbusSensor>(bus, path, ctx)),
Vijay Khemka7452a862020-08-11 16:01:23 -070070 paramType(dbusParam)
71 {}
72
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070073 /** @brief Get sensor value property from D-bus interface */
74 double getParamValue();
75
76 private:
Vijay Khemka7452a862020-08-11 16:01:23 -070077 std::unique_ptr<DbusSensor> dbusSensor = nullptr;
78 double value = 0;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070079 ParamType paramType;
80};
81
Matt Spinlerce675222021-01-14 16:38:09 -060082class VirtualSensor : public ValueObject
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070083{
84 public:
85 VirtualSensor() = delete;
86 virtual ~VirtualSensor() = default;
87
88 /** @brief Constructs VirtualSensor
89 *
90 * @param[in] bus - Handle to system dbus
91 * @param[in] objPath - The Dbus path of sensor
92 * @param[in] sensorConfig - Json object for sensor config
93 */
94 VirtualSensor(sdbusplus::bus::bus& bus, const char* objPath,
Vijay Khemka32a71562020-09-10 15:29:18 -070095 const Json& sensorConfig, const std::string& name) :
Rashmica Guptaa2fa63a2021-08-06 12:21:13 +100096 ValueObject(bus, objPath, action::defer_emit),
Vijay Khemka32a71562020-09-10 15:29:18 -070097 bus(bus), name(name)
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070098 {
Matt Spinlerce675222021-01-14 16:38:09 -060099 initVirtualSensor(sensorConfig, objPath);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700100 }
101
Rashmica Guptae7efe132021-07-27 19:42:11 +1000102 /** @brief Constructs VirtualSensor
103 *
104 * @param[in] bus - Handle to system dbus
105 * @param[in] objPath - The Dbus path of sensor
106 * @param[in] ifacemap - All the sensor information
107 * @param[in] name - Virtual sensor name
108 * @param[in] type - Virtual sensor type/unit
109 * @param[in] calcType - Calculation used to calculate sensor value
110 *
111 */
112 VirtualSensor(sdbusplus::bus::bus& bus, const char* objPath,
113 const InterfaceMap& ifacemap, const std::string& name,
114 const std::string& type, const std::string& calculationType) :
115 ValueObject(bus, objPath, action::defer_emit),
116 bus(bus), name(name)
117 {
118 initVirtualSensor(ifacemap, objPath, type, calculationType);
119 }
120
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700121 /** @brief Set sensor value */
122 void setSensorValue(double value);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700123 /** @brief Update sensor at regular intrval */
124 void updateVirtualSensor();
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000125 /** @brief Check if sensor value is in valid range */
126 bool sensorInRange(double value);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700127
128 /** @brief Map of list of parameters */
129 using ParamMap =
130 std::unordered_map<std::string, std::unique_ptr<SensorParam>>;
131 ParamMap paramMap;
132
133 private:
134 /** @brief sdbusplus bus client connection. */
135 sdbusplus::bus::bus& bus;
Vijay Khemka32a71562020-09-10 15:29:18 -0700136 /** @brief name of sensor */
137 std::string name;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700138 /** @brief Expression string for virtual sensor value calculations */
139 std::string exprStr;
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700140 /** @brief symbol table from exprtk */
141 exprtk::symbol_table<double> symbols{};
142 /** @brief expression from exprtk to calculate sensor value */
143 exprtk::expression<double> expression{};
Matt Spinler9f1ef4f2020-11-09 15:59:11 -0600144 /** @brief The vecops package so the expression can use vectors */
145 exprtk::rtl::vecops::package<double> vecopsPackage;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000146 /** @brief The maximum valid value for an input sensor **/
147 double maxValidInput = std::numeric_limits<double>::infinity();
148 /** @brief The minimum valid value for an input sensor **/
149 double minValidInput = -std::numeric_limits<double>::infinity();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700150
Matt Spinlerce675222021-01-14 16:38:09 -0600151 /** @brief The critical threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600152 std::unique_ptr<Threshold<CriticalObject>> criticalIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600153 /** @brief The warning threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600154 std::unique_ptr<Threshold<WarningObject>> warningIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600155 /** @brief The soft shutdown threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600156 std::unique_ptr<Threshold<SoftShutdownObject>> softShutdownIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600157 /** @brief The hard shutdown threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600158 std::unique_ptr<Threshold<HardShutdownObject>> hardShutdownIface;
Matt Spinlerb306b032021-02-01 10:05:46 -0600159 /** @brief The performance loss threshold interface object */
160 std::unique_ptr<Threshold<PerformanceLossObject>> perfLossIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600161
Lei YU0fcf0e12021-06-04 11:14:17 +0800162 /** @brief The association interface object */
163 std::unique_ptr<AssociationObject> associationIface;
164
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700165 /** @brief Read config from json object and initialize sensor data
166 * for each virtual sensor
167 */
Matt Spinlerce675222021-01-14 16:38:09 -0600168 void initVirtualSensor(const Json& sensorConfig,
169 const std::string& objPath);
170
Rashmica Guptae7efe132021-07-27 19:42:11 +1000171 /** @brief Read config from interface map and initialize sensor data
172 * for each virtual sensor
173 */
174 void initVirtualSensor(const InterfaceMap& interfaceMap,
175 const std::string& objPath,
176 const std::string& sensorType,
177 const std::string& calculationType);
178
179 /** @brief Returns which calculation function or expression to use */
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000180 double calculateValue(const std::string& sensortype,
181 const VirtualSensor::ParamMap& paramMap);
182 /** @brief Calculate median value from sensors */
183 double
184 calculateModifiedMedianValue(const VirtualSensor::ParamMap& paramMap);
Rashmica Gupta3e999192021-06-09 16:17:04 +1000185 /** @brief create threshold objects from json config */
186 void createThresholds(const Json& threshold, const std::string& objPath);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000187 /** @brief parse config from entity manager **/
188 void parseConfigInterface(const PropertyMap& propertyMap,
189 const std::string& sensorType,
190 const std::string& interface);
Rashmica Gupta3e999192021-06-09 16:17:04 +1000191
Vijay Khemka32a71562020-09-10 15:29:18 -0700192 /** @brief Check Sensor threshold and update alarm and log */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600193 template <typename V, typename T>
194 void checkThresholds(V value, T& threshold)
Matt Spinler8f5e6112021-01-15 10:44:32 -0600195 {
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600196 if (!threshold)
197 return;
Matt Spinler8f5e6112021-01-15 10:44:32 -0600198
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600199 static constexpr auto tname = T::element_type::name;
200
201 auto alarmHigh = threshold->alarmHigh();
Matt Spinlera4fe6652021-01-28 14:02:59 -0600202 if ((!alarmHigh && value >= threshold->high()) ||
203 (alarmHigh && value < threshold->high()))
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600204 {
205 if (!alarmHigh)
Matt Spinler8f5e6112021-01-15 10:44:32 -0600206 {
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600207 constexpr auto msg =
208 "ASSERT: {} has exceeded the {} high threshold";
209 log<level::ERR>(fmt::format(msg, name, tname).c_str());
George Hung4294e6d2021-04-14 20:58:21 +0800210 threshold->alarmHighSignalAsserted(value);
Matt Spinler8f5e6112021-01-15 10:44:32 -0600211 }
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600212 else
Matt Spinler8f5e6112021-01-15 10:44:32 -0600213 {
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600214 constexpr auto msg =
215 "DEASSERT: {} is under the {} high threshold";
216 log<level::INFO>(fmt::format(msg, name, tname).c_str());
George Hung4294e6d2021-04-14 20:58:21 +0800217 threshold->alarmHighSignalDeasserted(value);
Matt Spinler8f5e6112021-01-15 10:44:32 -0600218 }
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600219 threshold->alarmHigh(!alarmHigh);
220 }
221
222 auto alarmLow = threshold->alarmLow();
Matt Spinlera4fe6652021-01-28 14:02:59 -0600223 if ((!alarmLow && value <= threshold->low()) ||
224 (alarmLow && value > threshold->low()))
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600225 {
226 if (!alarmLow)
227 {
228 constexpr auto msg = "ASSERT: {} is under the {} low threshold";
229 log<level::ERR>(fmt::format(msg, name, tname).c_str());
George Hung4294e6d2021-04-14 20:58:21 +0800230 threshold->alarmLowSignalAsserted(value);
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600231 }
232 else
233 {
234 constexpr auto msg =
235 "DEASSERT: {} is above the {} low threshold";
236 log<level::INFO>(fmt::format(msg, name, tname).c_str());
George Hung4294e6d2021-04-14 20:58:21 +0800237 threshold->alarmLowSignalDeasserted(value);
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600238 }
239 threshold->alarmLow(!alarmLow);
Matt Spinler8f5e6112021-01-15 10:44:32 -0600240 }
241 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700242};
243
244class VirtualSensors
245{
246 public:
247 VirtualSensors() = delete;
248 virtual ~VirtualSensors() = default;
249
250 /** @brief Constructs VirtualSensors
251 *
252 * @param[in] bus - Handle to system dbus
253 */
254 explicit VirtualSensors(sdbusplus::bus::bus& bus) : bus(bus)
255 {
256 createVirtualSensors();
257 }
Rashmica Guptae7efe132021-07-27 19:42:11 +1000258 /** @brief Calls createVirtualSensor when interface added */
259 void propertiesChanged(sdbusplus::message::message& msg);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700260
261 private:
262 /** @brief sdbusplus bus client connection. */
263 sdbusplus::bus::bus& bus;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000264 /** @brief Get virual sensor config from DBus**/
265 ManagedObjectType getObjectsFromDBus();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700266 /** @brief Parsing virtual sensor config JSON file */
267 Json parseConfigFile(const std::string configFile);
268
Rashmica Guptae7efe132021-07-27 19:42:11 +1000269 /** @brief Matches for virtual sensors */
270 std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700271 /** @brief Map of the object VirtualSensor */
272 std::unordered_map<std::string, std::unique_ptr<VirtualSensor>>
273 virtualSensorsMap;
274
Rashmica Guptae7efe132021-07-27 19:42:11 +1000275 /** @brief Create list of virtual sensors from JSON config*/
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700276 void createVirtualSensors();
Rashmica Guptae7efe132021-07-27 19:42:11 +1000277 /** @brief Create list of virtual sensors from DBus config */
278 void createVirtualSensorsFromDBus(const std::string& calculationType);
279 /** @brief Setup matches for virtual sensors */
280 void setupMatches();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700281};
282
283} // namespace virtualSensor
284} // namespace phosphor