blob: 1b3683fe5c2e2138ccde74f959b29f5057393780 [file] [log] [blame]
Tao Linf2e94222023-10-31 17:38:17 +08001#pragma once
2
Vijay Khemka7452a862020-08-11 16:01:23 -07003#include "dbusSensor.hpp"
Vijay Khemka92d648b2020-08-21 18:55:07 -07004#include "exprtkTools.hpp"
Matt Spinler8f5e6112021-01-15 10:44:32 -06005#include "thresholds.hpp"
6
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07007#include <nlohmann/json.hpp>
Patrick Williams82b39c62021-07-28 16:22:27 -05008#include <phosphor-logging/lg2.hpp>
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07009#include <sdbusplus/bus.hpp>
Lei YU0fcf0e12021-06-04 11:14:17 +080010#include <xyz/openbmc_project/Association/Definitions/server.hpp>
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070011#include <xyz/openbmc_project/Sensor/Value/server.hpp>
12
13#include <map>
14#include <string>
15
Tao Linf2e94222023-10-31 17:38:17 +080016namespace phosphor::virtual_sensor
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070017{
18
Patrick Williams82b39c62021-07-28 16:22:27 -050019PHOSPHOR_LOG2_USING_WITH_FLAGS;
20
Rashmica Guptae7efe132021-07-27 19:42:11 +100021using 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
25using PropertyMap = std::map<std::string, BasicVariantType>;
26
27using InterfaceMap = std::map<std::string, PropertyMap>;
28
29using ManagedObjectType =
30 std::map<sdbusplus::message::object_path, InterfaceMap>;
31
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070032using Json = nlohmann::json;
Matt Spinlerce675222021-01-14 16:38:09 -060033
34template <typename... T>
Patrick Williams8e11ccc2022-07-22 19:26:57 -050035using ServerObject = typename sdbusplus::server::object_t<T...>;
Matt Spinlerce675222021-01-14 16:38:09 -060036
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070037using ValueIface = sdbusplus::xyz::openbmc_project::Sensor::server::Value;
Matt Spinlerce675222021-01-14 16:38:09 -060038using ValueObject = ServerObject<ValueIface>;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070039
Lei YU0fcf0e12021-06-04 11:14:17 +080040using AssociationIface =
41 sdbusplus::xyz::openbmc_project::Association::server::Definitions;
42using AssociationObject = ServerObject<AssociationIface>;
43
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070044class 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 */
Patrick Williams1226f202023-05-10 07:51:16 -050060 explicit SensorParam(double value) : value(value), paramType(constParam) {}
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070061
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 */
Tao Linf2e94222023-10-31 17:38:17 +080068 SensorParam(sdbusplus::bus_t& bus, const std::string& path,
69 VirtualSensor& ctx) :
Vijay Khemka51f898e2020-09-09 22:24:18 -070070 dbusSensor(std::make_unique<DbusSensor>(bus, path, ctx)),
Vijay Khemka7452a862020-08-11 16:01:23 -070071 paramType(dbusParam)
72 {}
73
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070074 /** @brief Get sensor value property from D-bus interface */
75 double getParamValue();
76
77 private:
Vijay Khemka7452a862020-08-11 16:01:23 -070078 std::unique_ptr<DbusSensor> dbusSensor = nullptr;
Tao Linf2e94222023-10-31 17:38:17 +080079
80 /** @brief virtual sensor value */
81 double value = std::numeric_limits<double>::quiet_NaN();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070082 ParamType paramType;
83};
84
Matt Spinlerce675222021-01-14 16:38:09 -060085class VirtualSensor : public ValueObject
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070086{
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
Amithash Prasad7d2f3232025-06-02 20:31:48 -070096 * @param[in] name - Sensor name
97 * @param[in] type - sensor type/unit
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070098 */
Patrick Williams8e11ccc2022-07-22 19:26:57 -050099 VirtualSensor(sdbusplus::bus_t& bus, const char* objPath,
Amithash Prasad7d2f3232025-06-02 20:31:48 -0700100 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)
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700104 {
Amithash Prasad7d2f3232025-06-02 20:31:48 -0700105 initVirtualSensor(sensorConfig, objPath, type);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700106 }
107
Rashmica Guptae7efe132021-07-27 19:42:11 +1000108 /** @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
Tao Lindc777012022-07-27 20:41:46 +0800116 * @param[in] entityPath - Virtual sensor path in entityManager Dbus
Rashmica Guptae7efe132021-07-27 19:42:11 +1000117 *
118 */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500119 VirtualSensor(sdbusplus::bus_t& bus, const char* objPath,
Rashmica Guptae7efe132021-07-27 19:42:11 +1000120 const InterfaceMap& ifacemap, const std::string& name,
Tao Lindc777012022-07-27 20:41:46 +0800121 const std::string& type, const std::string& calculationType,
122 const std::string& entityPath) :
Patrick Williams150d5f62024-08-16 15:21:45 -0400123 ValueObject(bus, objPath, action::defer_emit), bus(bus), name(name),
Amithash Prasad7d2f3232025-06-02 20:31:48 -0700124 objPath(objPath), entityPath(entityPath)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000125 {
126 initVirtualSensor(ifacemap, objPath, type, calculationType);
127 }
128
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700129 /** @brief Set sensor value */
130 void setSensorValue(double value);
Tao Linf2e94222023-10-31 17:38:17 +0800131
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700132 /** @brief Update sensor at regular intrval */
133 void updateVirtualSensor();
Tao Linf2e94222023-10-31 17:38:17 +0800134
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000135 /** @brief Check if sensor value is in valid range */
136 bool sensorInRange(double value);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700137
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. */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500145 sdbusplus::bus_t& bus;
Vijay Khemka32a71562020-09-10 15:29:18 -0700146 /** @brief name of sensor */
147 std::string name;
Amithash Prasad7d2f3232025-06-02 20:31:48 -0700148 /** @brief unit of sensor */
149 ValueIface::Unit units;
150 /** @brief object path of this sensor */
151 std::string objPath;
Tao Lindc777012022-07-27 20:41:46 +0800152
153 /** @brief Virtual sensor path in entityManager Dbus.
154 * This value is used to set thresholds/create association
155 */
156 std::string entityPath;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700157 /** @brief Expression string for virtual sensor value calculations */
158 std::string exprStr;
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700159 /** @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{};
Matt Spinler9f1ef4f2020-11-09 15:59:11 -0600163 /** @brief The vecops package so the expression can use vectors */
164 exprtk::rtl::vecops::package<double> vecopsPackage;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000165 /** @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();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700169
Matt Spinlerce675222021-01-14 16:38:09 -0600170 /** @brief The critical threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600171 std::unique_ptr<Threshold<CriticalObject>> criticalIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600172 /** @brief The warning threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600173 std::unique_ptr<Threshold<WarningObject>> warningIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600174 /** @brief The soft shutdown threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600175 std::unique_ptr<Threshold<SoftShutdownObject>> softShutdownIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600176 /** @brief The hard shutdown threshold interface object */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600177 std::unique_ptr<Threshold<HardShutdownObject>> hardShutdownIface;
Matt Spinlerb306b032021-02-01 10:05:46 -0600178 /** @brief The performance loss threshold interface object */
179 std::unique_ptr<Threshold<PerformanceLossObject>> perfLossIface;
Matt Spinlerce675222021-01-14 16:38:09 -0600180
Lei YU0fcf0e12021-06-04 11:14:17 +0800181 /** @brief The association interface object */
182 std::unique_ptr<AssociationObject> associationIface;
183
Lei YU0ab9d832022-07-19 07:12:50 +0000184 static FuncMaxIgnoreNaN<double> funcMaxIgnoreNaN;
Lei YU87d35112022-10-24 05:54:25 +0000185 static FuncSumIgnoreNaN<double> funcSumIgnoreNaN;
Lei YUc77b6b32023-06-08 12:02:05 +0000186 static FuncIfNan<double> funcIfNan;
Lei YU0ab9d832022-07-19 07:12:50 +0000187
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700188 /** @brief Read config from json object and initialize sensor data
189 * for each virtual sensor
190 */
Amithash Prasad7d2f3232025-06-02 20:31:48 -0700191 void initVirtualSensor(const Json& sensorConfig, const std::string& objPath,
192 const std::string& type);
Matt Spinlerce675222021-01-14 16:38:09 -0600193
Rashmica Guptae7efe132021-07-27 19:42:11 +1000194 /** @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 */
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000203 double calculateValue(const std::string& sensortype,
204 const VirtualSensor::ParamMap& paramMap);
Rashmica Gupta3e999192021-06-09 16:17:04 +1000205 /** @brief create threshold objects from json config */
Amithash Prasad7d2f3232025-06-02 20:31:48 -0700206 void createThresholds(const Json& threshold, const std::string& objPath,
207 ValueIface::Unit units);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000208 /** @brief parse config from entity manager **/
209 void parseConfigInterface(const PropertyMap& propertyMap,
210 const std::string& sensorType,
211 const std::string& interface);
Rashmica Gupta3e999192021-06-09 16:17:04 +1000212
Amithash Prasadb3f59462025-06-02 21:22:13 -0700213 /** @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 */
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600217 template <typename V, typename T>
Amithash Prasadb3f59462025-06-02 21:22:13 -0700218 bool checkThresholds(V value, T& threshold, bool& change)
Matt Spinler8f5e6112021-01-15 10:44:32 -0600219 {
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600220 if (!threshold)
Amithash Prasadb3f59462025-06-02 21:22:13 -0700221 return true;
Matt Spinler8f5e6112021-01-15 10:44:32 -0600222
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600223 static constexpr auto tname = T::element_type::name;
224
225 auto alarmHigh = threshold->alarmHigh();
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000226 auto highHysteresis = threshold->getHighHysteresis();
Matt Spinlera4fe6652021-01-28 14:02:59 -0600227 if ((!alarmHigh && value >= threshold->high()) ||
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000228 (alarmHigh && value < (threshold->high() - highHysteresis)))
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600229 {
Amithash Prasadb3f59462025-06-02 21:22:13 -0700230 change = true;
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600231 if (!alarmHigh)
Matt Spinler8f5e6112021-01-15 10:44:32 -0600232 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500233 error("ASSERT: sensor {SENSOR} is above the upper threshold "
234 "{THRESHOLD}.",
235 "SENSOR", name, "THRESHOLD", tname);
George Hung4294e6d2021-04-14 20:58:21 +0800236 threshold->alarmHighSignalAsserted(value);
Matt Spinler8f5e6112021-01-15 10:44:32 -0600237 }
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600238 else
Matt Spinler8f5e6112021-01-15 10:44:32 -0600239 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500240 info("DEASSERT: sensor {SENSOR} is under the upper threshold "
241 "{THRESHOLD}.",
242 "SENSOR", name, "THRESHOLD", tname);
George Hung4294e6d2021-04-14 20:58:21 +0800243 threshold->alarmHighSignalDeasserted(value);
Matt Spinler8f5e6112021-01-15 10:44:32 -0600244 }
Amithash Prasadb3f59462025-06-02 21:22:13 -0700245 alarmHigh = !alarmHigh;
246 threshold->alarmHigh(alarmHigh);
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600247 }
248
249 auto alarmLow = threshold->alarmLow();
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000250 auto lowHysteresis = threshold->getLowHysteresis();
Matt Spinlera4fe6652021-01-28 14:02:59 -0600251 if ((!alarmLow && value <= threshold->low()) ||
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000252 (alarmLow && value > (threshold->low() + lowHysteresis)))
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600253 {
Amithash Prasadb3f59462025-06-02 21:22:13 -0700254 change = true;
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600255 if (!alarmLow)
256 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500257 error("ASSERT: sensor {SENSOR} is below the lower threshold "
258 "{THRESHOLD}.",
259 "SENSOR", name, "THRESHOLD", tname);
George Hung4294e6d2021-04-14 20:58:21 +0800260 threshold->alarmLowSignalAsserted(value);
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600261 }
262 else
263 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500264 info("DEASSERT: sensor {SENSOR} is above the lower threshold "
265 "{THRESHOLD}.",
266 "SENSOR", name, "THRESHOLD", tname);
George Hung4294e6d2021-04-14 20:58:21 +0800267 threshold->alarmLowSignalDeasserted(value);
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600268 }
Amithash Prasadb3f59462025-06-02 21:22:13 -0700269 alarmLow = !alarmLow;
270 threshold->alarmLow(alarmLow);
Matt Spinler8f5e6112021-01-15 10:44:32 -0600271 }
Amithash Prasadb3f59462025-06-02 21:22:13 -0700272 return !alarmHigh && !alarmLow;
Matt Spinler8f5e6112021-01-15 10:44:32 -0600273 }
Tao Lindc777012022-07-27 20:41:46 +0800274
275 /** @brief Create Association from entityPath*/
276 void createAssociation(const std::string& objPath,
277 const std::string& entityPath);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700278};
279
280class 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 */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500290 explicit VirtualSensors(sdbusplus::bus_t& bus) : bus(bus)
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700291 {
292 createVirtualSensors();
293 }
Rashmica Guptae7efe132021-07-27 19:42:11 +1000294 /** @brief Calls createVirtualSensor when interface added */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500295 void propertiesChanged(sdbusplus::message_t& msg);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700296
297 private:
298 /** @brief sdbusplus bus client connection. */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500299 sdbusplus::bus_t& bus;
Manojkiran Eda5f07fa32024-06-17 14:26:17 +0530300 /** @brief Get virtual sensor config from DBus**/
Rashmica Guptae7efe132021-07-27 19:42:11 +1000301 ManagedObjectType getObjectsFromDBus();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700302 /** @brief Parsing virtual sensor config JSON file */
Patrick Williams32dff212023-02-09 13:54:18 -0600303 Json parseConfigFile();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700304
Rashmica Guptae7efe132021-07-27 19:42:11 +1000305 /** @brief Matches for virtual sensors */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500306 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700307 /** @brief Map of the object VirtualSensor */
308 std::unordered_map<std::string, std::unique_ptr<VirtualSensor>>
309 virtualSensorsMap;
310
Rashmica Guptae7efe132021-07-27 19:42:11 +1000311 /** @brief Create list of virtual sensors from JSON config*/
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700312 void createVirtualSensors();
Rashmica Guptae7efe132021-07-27 19:42:11 +1000313 /** @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();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700317};
318
Tao Linf2e94222023-10-31 17:38:17 +0800319} // namespace phosphor::virtual_sensor