blob: e77343383afaeb87499bc2d29ec0767d6b314a36 [file] [log] [blame]
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001#include "virtualSensor.hpp"
2
Patrick Williams82b39c62021-07-28 16:22:27 -05003#include <phosphor-logging/lg2.hpp>
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07004
5#include <fstream>
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07006
7static constexpr bool DEBUG = false;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07008static constexpr auto sensorDbusPath = "/xyz/openbmc_project/sensors/";
Rashmica Guptae7efe132021-07-27 19:42:11 +10009static constexpr auto vsThresholdsIfaceSuffix = ".Thresholds";
Tao Linf6b7e0a2022-10-09 09:35:44 +080010static constexpr std::array<const char*, 2> calculationIfaces = {
11 "xyz.openbmc_project.Configuration.ModifiedMedian",
12 "xyz.openbmc_project.Configuration.Maximum"};
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +100013static constexpr auto defaultHysteresis = 0;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070014
Patrick Williams82b39c62021-07-28 16:22:27 -050015PHOSPHOR_LOG2_USING_WITH_FLAGS;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070016
Vijay Khemka51f898e2020-09-09 22:24:18 -070017int handleDbusSignal(sd_bus_message* msg, void* usrData, sd_bus_error*)
18{
19 if (usrData == nullptr)
20 {
21 throw std::runtime_error("Invalid match");
22 }
23
Patrick Williams8e11ccc2022-07-22 19:26:57 -050024 auto sdbpMsg = sdbusplus::message_t(msg);
Vijay Khemka51f898e2020-09-09 22:24:18 -070025 std::string msgIfce;
26 std::map<std::string, std::variant<int64_t, double, bool>> msgData;
27
28 sdbpMsg.read(msgIfce, msgData);
29
30 if (msgData.find("Value") != msgData.end())
31 {
32 using namespace phosphor::virtualSensor;
33 VirtualSensor* obj = static_cast<VirtualSensor*>(usrData);
34 // TODO(openbmc/phosphor-virtual-sensor#1): updateVirtualSensor should
35 // be changed to take the information we got from the signal, to avoid
36 // having to do numerous dbus queries.
37 obj->updateVirtualSensor();
38 }
39 return 0;
40}
41
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070042namespace phosphor
43{
44namespace virtualSensor
45{
46
Lei YU0ab9d832022-07-19 07:12:50 +000047FuncMaxIgnoreNaN<double> VirtualSensor::funcMaxIgnoreNaN;
Lei YU87d35112022-10-24 05:54:25 +000048FuncSumIgnoreNaN<double> VirtualSensor::funcSumIgnoreNaN;
Lei YUc77b6b32023-06-08 12:02:05 +000049FuncIfNan<double> VirtualSensor::funcIfNan;
Lei YU0ab9d832022-07-19 07:12:50 +000050
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070051void printParams(const VirtualSensor::ParamMap& paramMap)
52{
53 for (const auto& p : paramMap)
54 {
55 const auto& p1 = p.first;
56 const auto& p2 = p.second;
57 auto val = p2->getParamValue();
Patrick Williamsfbd71452021-08-30 06:59:46 -050058 debug("Parameter: {PARAM} = {VALUE}", "PARAM", p1, "VALUE", val);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070059 }
60}
61
62double SensorParam::getParamValue()
63{
64 switch (paramType)
65 {
66 case constParam:
67 return value;
68 break;
Vijay Khemka7452a862020-08-11 16:01:23 -070069 case dbusParam:
70 return dbusSensor->getSensorValue();
71 break;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070072 default:
73 throw std::invalid_argument("param type not supported");
74 }
75}
76
Lei YU0fcf0e12021-06-04 11:14:17 +080077using AssociationList =
78 std::vector<std::tuple<std::string, std::string, std::string>>;
79
80AssociationList getAssociationsFromJson(const Json& j)
81{
82 AssociationList assocs{};
83 try
84 {
85 j.get_to(assocs);
86 }
87 catch (const std::exception& ex)
88 {
Patrick Williams82b39c62021-07-28 16:22:27 -050089 error("Failed to parse association: {ERROR}", "ERROR", ex);
Lei YU0fcf0e12021-06-04 11:14:17 +080090 }
91 return assocs;
92}
93
Rashmica Guptae7efe132021-07-27 19:42:11 +100094template <typename U>
95struct VariantToNumber
96{
97 template <typename T>
98 U operator()(const T& t) const
99 {
100 if constexpr (std::is_convertible<T, U>::value)
101 {
102 return static_cast<U>(t);
103 }
104 throw std::invalid_argument("Invalid number type in config\n");
105 }
106};
107
108template <typename U>
109U getNumberFromConfig(const PropertyMap& map, const std::string& name,
Jiaqing Zhao190f6d02022-05-21 23:26:15 +0800110 bool required,
111 U defaultValue = std::numeric_limits<U>::quiet_NaN())
Rashmica Guptae7efe132021-07-27 19:42:11 +1000112{
113 if (auto itr = map.find(name); itr != map.end())
114 {
115 return std::visit(VariantToNumber<U>(), itr->second);
116 }
117 else if (required)
118 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500119 error("Required field {NAME} missing in config", "NAME", name);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000120 throw std::invalid_argument("Required field missing in config");
121 }
Jiaqing Zhao190f6d02022-05-21 23:26:15 +0800122 return defaultValue;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000123}
124
125bool isCalculationType(const std::string& interface)
126{
127 auto itr = std::find(calculationIfaces.begin(), calculationIfaces.end(),
128 interface);
129 if (itr != calculationIfaces.end())
130 {
131 return true;
132 }
133 return false;
134}
135
136const std::string getThresholdType(const std::string& direction,
Rashmica Gupta05b1d412021-11-03 12:01:36 +1100137 const std::string& severity)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000138{
Rashmica Guptae7efe132021-07-27 19:42:11 +1000139 std::string suffix;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000140
141 if (direction == "less than")
142 {
143 suffix = "Low";
144 }
145 else if (direction == "greater than")
146 {
147 suffix = "High";
148 }
149 else
150 {
151 throw std::invalid_argument(
152 "Invalid threshold direction specified in entity manager");
153 }
Rashmica Gupta05b1d412021-11-03 12:01:36 +1100154 return severity + suffix;
155}
156
157std::string getSeverityField(const PropertyMap& propertyMap)
158{
159 static const std::array thresholdTypes{"Warning", "Critical",
160 "PerformanceLoss", "SoftShutdown",
161 "HardShutdown"};
162
163 std::string severity;
164 if (auto itr = propertyMap.find("Severity"); itr != propertyMap.end())
165 {
166 /* Severity should be a string, but can be an unsigned int */
167 if (std::holds_alternative<std::string>(itr->second))
168 {
169 severity = std::get<std::string>(itr->second);
170 if (0 == std::ranges::count(thresholdTypes, severity))
171 {
172 throw std::invalid_argument(
173 "Invalid threshold severity specified in entity manager");
174 }
175 }
176 else
177 {
Patrick Williams1226f202023-05-10 07:51:16 -0500178 auto sev = getNumberFromConfig<uint64_t>(propertyMap, "Severity",
179 true);
Rashmica Gupta05b1d412021-11-03 12:01:36 +1100180 /* Checking bounds ourselves so we throw invalid argument on
181 * invalid user input */
182 if (sev >= thresholdTypes.size())
183 {
184 throw std::invalid_argument(
185 "Invalid threshold severity specified in entity manager");
186 }
187 severity = thresholdTypes.at(sev);
188 }
189 }
190 return severity;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000191}
192
Tao Lin91799db2022-07-27 21:02:20 +0800193void parseThresholds(Json& thresholds, const PropertyMap& propertyMap,
194 const std::string& entityInterface = "")
Rashmica Guptae7efe132021-07-27 19:42:11 +1000195{
196 std::string direction;
197
Rashmica Guptae7efe132021-07-27 19:42:11 +1000198 auto value = getNumberFromConfig<double>(propertyMap, "Value", true);
199
Rashmica Gupta05b1d412021-11-03 12:01:36 +1100200 auto severity = getSeverityField(propertyMap);
201
202 if (auto itr = propertyMap.find("Direction"); itr != propertyMap.end())
Rashmica Guptae7efe132021-07-27 19:42:11 +1000203 {
204 direction = std::get<std::string>(itr->second);
205 }
206
207 auto threshold = getThresholdType(direction, severity);
208 thresholds[threshold] = value;
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000209
Patrick Williams1226f202023-05-10 07:51:16 -0500210 auto hysteresis = getNumberFromConfig<double>(propertyMap, "Hysteresis",
211 false);
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000212 if (hysteresis != std::numeric_limits<double>::quiet_NaN())
213 {
214 thresholds[threshold + "Hysteresis"] = hysteresis;
215 }
Tao Lin91799db2022-07-27 21:02:20 +0800216
217 if (!entityInterface.empty())
218 {
219 thresholds[threshold + "Direction"] = entityInterface;
220 }
Rashmica Guptae7efe132021-07-27 19:42:11 +1000221}
222
223void VirtualSensor::parseConfigInterface(const PropertyMap& propertyMap,
224 const std::string& sensorType,
225 const std::string& interface)
226{
227 /* Parse sensors / DBus params */
228 if (auto itr = propertyMap.find("Sensors"); itr != propertyMap.end())
229 {
230 auto sensors = std::get<std::vector<std::string>>(itr->second);
231 for (auto sensor : sensors)
232 {
233 std::replace(sensor.begin(), sensor.end(), ' ', '_');
234 auto sensorObjPath = sensorDbusPath + sensorType + "/" + sensor;
235
Patrick Williams1226f202023-05-10 07:51:16 -0500236 auto paramPtr = std::make_unique<SensorParam>(bus, sensorObjPath,
237 this);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000238 symbols.create_variable(sensor);
239 paramMap.emplace(std::move(sensor), std::move(paramPtr));
240 }
241 }
242 /* Get expression string */
243 if (!isCalculationType(interface))
244 {
245 throw std::invalid_argument("Invalid expression in interface");
246 }
247 exprStr = interface;
248
249 /* Get optional min and max input and output values */
250 ValueIface::maxValue(
251 getNumberFromConfig<double>(propertyMap, "MaxValue", false));
252 ValueIface::minValue(
253 getNumberFromConfig<double>(propertyMap, "MinValue", false));
254 maxValidInput =
Jiaqing Zhao190f6d02022-05-21 23:26:15 +0800255 getNumberFromConfig<double>(propertyMap, "MaxValidInput", false,
256 std::numeric_limits<double>::infinity());
Rashmica Guptae7efe132021-07-27 19:42:11 +1000257 minValidInput =
Jiaqing Zhao190f6d02022-05-21 23:26:15 +0800258 getNumberFromConfig<double>(propertyMap, "MinValidInput", false,
259 -std::numeric_limits<double>::infinity());
Rashmica Guptae7efe132021-07-27 19:42:11 +1000260}
261
Matt Spinlerce675222021-01-14 16:38:09 -0600262void VirtualSensor::initVirtualSensor(const Json& sensorConfig,
263 const std::string& objPath)
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700264{
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700265 static const Json empty{};
266
267 /* Get threshold values if defined in config */
268 auto threshold = sensorConfig.value("Threshold", empty);
Matt Spinlerf15189e2021-01-15 10:13:28 -0600269
Rashmica Gupta3e999192021-06-09 16:17:04 +1000270 createThresholds(threshold, objPath);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700271
Harvey Wuf6443742021-04-09 16:47:36 +0800272 /* Get MaxValue, MinValue setting if defined in config */
273 auto confDesc = sensorConfig.value("Desc", empty);
274 if (auto maxConf = confDesc.find("MaxValue");
275 maxConf != confDesc.end() && maxConf->is_number())
276 {
277 ValueIface::maxValue(maxConf->get<double>());
278 }
279 if (auto minConf = confDesc.find("MinValue");
280 minConf != confDesc.end() && minConf->is_number())
281 {
282 ValueIface::minValue(minConf->get<double>());
283 }
284
Lei YU0fcf0e12021-06-04 11:14:17 +0800285 /* Get optional association */
286 auto assocJson = sensorConfig.value("Associations", empty);
287 if (!assocJson.empty())
288 {
289 auto assocs = getAssociationsFromJson(assocJson);
290 if (!assocs.empty())
291 {
292 associationIface =
293 std::make_unique<AssociationObject>(bus, objPath.c_str());
294 associationIface->associations(assocs);
295 }
296 }
297
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700298 /* Get expression string */
Patrick Williams03c4c8e2022-04-14 22:19:44 -0500299 static constexpr auto exprKey = "Expression";
300 if (sensorConfig.contains(exprKey))
301 {
Patrick Williamsa9596782022-04-15 10:20:07 -0500302 auto& ref = sensorConfig.at(exprKey);
Patrick Williams03c4c8e2022-04-14 22:19:44 -0500303 if (ref.is_array())
304 {
305 exprStr = std::string{};
306 for (auto& s : ref)
307 {
308 exprStr += s;
309 }
310 }
311 else if (ref.is_string())
312 {
313 exprStr = std::string{ref};
314 }
315 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700316
317 /* Get all the parameter listed in configuration */
318 auto params = sensorConfig.value("Params", empty);
319
320 /* Check for constant parameter */
321 const auto& consParams = params.value("ConstParam", empty);
322 if (!consParams.empty())
323 {
324 for (auto& j : consParams)
325 {
326 if (j.find("ParamName") != j.end())
327 {
328 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700329 std::string name = j["ParamName"];
330 symbols.create_variable(name);
331 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700332 }
333 else
334 {
335 /* Invalid configuration */
336 throw std::invalid_argument(
337 "ParamName not found in configuration");
338 }
339 }
340 }
341
Vijay Khemka7452a862020-08-11 16:01:23 -0700342 /* Check for dbus parameter */
343 auto dbusParams = params.value("DbusParam", empty);
344 if (!dbusParams.empty())
345 {
346 for (auto& j : dbusParams)
347 {
348 /* Get parameter dbus sensor descriptor */
349 auto desc = j.value("Desc", empty);
350 if ((!desc.empty()) && (j.find("ParamName") != j.end()))
351 {
352 std::string sensorType = desc.value("SensorType", "");
353 std::string name = desc.value("Name", "");
354
355 if (!sensorType.empty() && !name.empty())
356 {
George Liu1204b432021-12-29 17:24:48 +0800357 auto path = sensorDbusPath + sensorType + "/" + name;
Vijay Khemka7452a862020-08-11 16:01:23 -0700358
Patrick Williams1226f202023-05-10 07:51:16 -0500359 auto paramPtr = std::make_unique<SensorParam>(bus, path,
360 this);
George Liu1204b432021-12-29 17:24:48 +0800361 std::string paramName = j["ParamName"];
362 symbols.create_variable(paramName);
363 paramMap.emplace(std::move(paramName), std::move(paramPtr));
Vijay Khemka7452a862020-08-11 16:01:23 -0700364 }
365 }
366 }
367 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700368
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700369 symbols.add_constants();
Matt Spinler9f1ef4f2020-11-09 15:59:11 -0600370 symbols.add_package(vecopsPackage);
Lei YU0ab9d832022-07-19 07:12:50 +0000371 symbols.add_function("maxIgnoreNaN", funcMaxIgnoreNaN);
Lei YU87d35112022-10-24 05:54:25 +0000372 symbols.add_function("sumIgnoreNaN", funcSumIgnoreNaN);
Lei YUc77b6b32023-06-08 12:02:05 +0000373 symbols.add_function("ifNan", funcIfNan);
Lei YU0ab9d832022-07-19 07:12:50 +0000374
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700375 expression.register_symbol_table(symbols);
376
377 /* parser from exprtk */
378 exprtk::parser<double> parser{};
Matt Spinlerddc6dcd2020-11-09 11:16:31 -0600379 if (!parser.compile(exprStr, expression))
380 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500381 error("Expression compilation failed");
Matt Spinlerddc6dcd2020-11-09 11:16:31 -0600382
383 for (std::size_t i = 0; i < parser.error_count(); ++i)
384 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500385 auto err = parser.get_error(i);
386 error("Error parsing token at {POSITION}: {ERROR}", "POSITION",
387 err.token.position, "TYPE",
388 exprtk::parser_error::to_str(err.mode), "ERROR",
389 err.diagnostic);
Matt Spinlerddc6dcd2020-11-09 11:16:31 -0600390 }
391 throw std::runtime_error("Expression compilation failed");
392 }
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700393
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700394 /* Print all parameters for debug purpose only */
395 if (DEBUG)
396 printParams(paramMap);
397}
398
Tao Lindc777012022-07-27 20:41:46 +0800399void VirtualSensor::createAssociation(const std::string& objPath,
400 const std::string& entityPath)
401{
402 if (objPath.empty() || entityPath.empty())
403 {
404 return;
405 }
406
407 std::filesystem::path p(entityPath);
408 auto assocsDbus =
409 AssociationList{{"chassis", "all_sensors", p.parent_path().string()}};
Patrick Williams1226f202023-05-10 07:51:16 -0500410 associationIface = std::make_unique<AssociationObject>(bus,
411 objPath.c_str());
Tao Lindc777012022-07-27 20:41:46 +0800412 associationIface->associations(assocsDbus);
413}
414
Rashmica Guptae7efe132021-07-27 19:42:11 +1000415void VirtualSensor::initVirtualSensor(const InterfaceMap& interfaceMap,
416 const std::string& objPath,
417 const std::string& sensorType,
418 const std::string& calculationIface)
419{
420 Json thresholds;
Patrick Williams1226f202023-05-10 07:51:16 -0500421 const std::string vsThresholdsIntf = calculationIface +
422 vsThresholdsIfaceSuffix;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000423
424 for (const auto& [interface, propertyMap] : interfaceMap)
425 {
426 /* Each threshold is on it's own interface with a number as a suffix
427 * eg xyz.openbmc_project.Configuration.ModifiedMedian.Thresholds1 */
428 if (interface.find(vsThresholdsIntf) != std::string::npos)
429 {
Tao Lin91799db2022-07-27 21:02:20 +0800430 parseThresholds(thresholds, propertyMap, interface);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000431 }
432 else if (interface == calculationIface)
433 {
434 parseConfigInterface(propertyMap, sensorType, interface);
435 }
436 }
437
438 createThresholds(thresholds, objPath);
439 symbols.add_constants();
440 symbols.add_package(vecopsPackage);
441 expression.register_symbol_table(symbols);
442
Tao Lindc777012022-07-27 20:41:46 +0800443 createAssociation(objPath, entityPath);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000444 /* Print all parameters for debug purpose only */
445 if (DEBUG)
446 {
447 printParams(paramMap);
448 }
449}
450
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700451void VirtualSensor::setSensorValue(double value)
452{
Patrick Williams543bf662021-04-29 09:03:53 -0500453 value = std::clamp(value, ValueIface::minValue(), ValueIface::maxValue());
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700454 ValueIface::value(value);
455}
456
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000457double VirtualSensor::calculateValue(const std::string& calculation,
458 const VirtualSensor::ParamMap& paramMap)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000459{
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000460 auto itr = std::find(calculationIfaces.begin(), calculationIfaces.end(),
461 calculation);
462 if (itr == calculationIfaces.end())
463 {
464 return std::numeric_limits<double>::quiet_NaN();
465 }
466 else if (calculation == "xyz.openbmc_project.Configuration.ModifiedMedian")
467 {
468 return calculateModifiedMedianValue(paramMap);
469 }
Tao Linf6b7e0a2022-10-09 09:35:44 +0800470 else if (calculation == "xyz.openbmc_project.Configuration.Maximum")
471 {
472 return calculateMaximumValue(paramMap);
473 }
Rashmica Guptae7efe132021-07-27 19:42:11 +1000474 return std::numeric_limits<double>::quiet_NaN();
475}
476
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000477bool VirtualSensor::sensorInRange(double value)
478{
479 if (value <= this->maxValidInput && value >= this->minValidInput)
480 {
481 return true;
482 }
483 return false;
484}
485
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700486void VirtualSensor::updateVirtualSensor()
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700487{
488 for (auto& param : paramMap)
489 {
490 auto& name = param.first;
491 auto& data = param.second;
492 if (auto var = symbols.get_variable(name))
493 {
494 var->ref() = data->getParamValue();
495 }
496 else
497 {
498 /* Invalid parameter */
499 throw std::invalid_argument("ParamName not found in symbols");
500 }
501 }
Patrick Williams1226f202023-05-10 07:51:16 -0500502 auto itr = std::find(calculationIfaces.begin(), calculationIfaces.end(),
503 exprStr);
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000504 auto val = (itr == calculationIfaces.end())
505 ? expression.value()
506 : calculateValue(exprStr, paramMap);
Vijay Khemka32a71562020-09-10 15:29:18 -0700507
508 /* Set sensor value to dbus interface */
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700509 setSensorValue(val);
Vijay Khemka32a71562020-09-10 15:29:18 -0700510
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700511 if (DEBUG)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000512 {
Patrick Williamsfbd71452021-08-30 06:59:46 -0500513 debug("Sensor {NAME} = {VALUE}", "NAME", this->name, "VALUE", val);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000514 }
Vijay Khemka32a71562020-09-10 15:29:18 -0700515
Matt Spinler8f5e6112021-01-15 10:44:32 -0600516 /* Check sensor thresholds and log required message */
Matt Spinlerb306b032021-02-01 10:05:46 -0600517 checkThresholds(val, perfLossIface);
Patrick Williamsfdb826d2021-01-20 14:37:53 -0600518 checkThresholds(val, warningIface);
519 checkThresholds(val, criticalIface);
520 checkThresholds(val, softShutdownIface);
521 checkThresholds(val, hardShutdownIface);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700522}
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700523
Rashmica Gupta304fd0e2021-08-10 16:50:44 +1000524double VirtualSensor::calculateModifiedMedianValue(
525 const VirtualSensor::ParamMap& paramMap)
526{
527 std::vector<double> values;
528
529 for (auto& param : paramMap)
530 {
531 auto& name = param.first;
532 if (auto var = symbols.get_variable(name))
533 {
534 if (!sensorInRange(var->ref()))
535 {
536 continue;
537 }
538 values.push_back(var->ref());
539 }
540 }
541
542 size_t size = values.size();
543 std::sort(values.begin(), values.end());
544 switch (size)
545 {
546 case 2:
547 /* Choose biggest value */
548 return values.at(1);
549 case 0:
550 return std::numeric_limits<double>::quiet_NaN();
551 default:
552 /* Choose median value */
553 if (size % 2 == 0)
554 {
555 // Average of the two middle values
556 return (values.at(size / 2) + values.at(size / 2 - 1)) / 2;
557 }
558 else
559 {
560 return values.at((size - 1) / 2);
561 }
562 }
563}
564
Tao Linf6b7e0a2022-10-09 09:35:44 +0800565double VirtualSensor::calculateMaximumValue(
566 const VirtualSensor::ParamMap& paramMap)
567{
568 std::vector<double> values;
569
570 for (auto& param : paramMap)
571 {
572 auto& name = param.first;
573 if (auto var = symbols.get_variable(name))
574 {
575 if (!sensorInRange(var->ref()))
576 {
577 continue;
578 }
579 values.push_back(var->ref());
580 }
581 }
582 auto maxIt = std::max_element(values.begin(), values.end());
583 if (maxIt == values.end())
584 {
585 return std::numeric_limits<double>::quiet_NaN();
586 }
587 return *maxIt;
588}
589
Rashmica Gupta3e999192021-06-09 16:17:04 +1000590void VirtualSensor::createThresholds(const Json& threshold,
591 const std::string& objPath)
592{
593 if (threshold.empty())
594 {
595 return;
596 }
597 // Only create the threshold interfaces if
598 // at least one of their values is present.
599 if (threshold.contains("CriticalHigh") || threshold.contains("CriticalLow"))
600 {
601 criticalIface =
602 std::make_unique<Threshold<CriticalObject>>(bus, objPath.c_str());
603
Tao Lin91799db2022-07-27 21:02:20 +0800604 if (threshold.contains("CriticalHigh"))
605 {
606 criticalIface->setEntityInterfaceHigh(
607 threshold.value("CriticalHighDirection", ""));
608 if (DEBUG)
609 {
610 debug("Sensor Threshold:{NAME} = intf:{INTF}", "NAME", objPath,
611 "INTF", threshold.value("CriticalHighDirection", ""));
612 }
613 }
614 if (threshold.contains("CriticalLow"))
615 {
616 criticalIface->setEntityInterfaceLow(
617 threshold.value("CriticalLowDirection", ""));
618 if (DEBUG)
619 {
620 debug("Sensor Threshold:{NAME} = intf:{INTF}", "NAME", objPath,
621 "INTF", threshold.value("CriticalLowDirection", ""));
622 }
623 }
624
625 criticalIface->setEntityPath(entityPath);
626 if (DEBUG)
627 {
628 debug("Sensor Threshold:{NAME} = path:{PATH}", "NAME", objPath,
629 "PATH", entityPath);
630 }
Matt Spinlera291ce12023-02-06 15:12:44 -0600631
632 criticalIface->criticalHigh(threshold.value(
633 "CriticalHigh", std::numeric_limits<double>::quiet_NaN()));
634 criticalIface->criticalLow(threshold.value(
635 "CriticalLow", std::numeric_limits<double>::quiet_NaN()));
636 criticalIface->setHighHysteresis(
637 threshold.value("CriticalHighHysteresis", defaultHysteresis));
638 criticalIface->setLowHysteresis(
639 threshold.value("CriticalLowHysteresis", defaultHysteresis));
Rashmica Gupta3e999192021-06-09 16:17:04 +1000640 }
641
642 if (threshold.contains("WarningHigh") || threshold.contains("WarningLow"))
643 {
644 warningIface =
645 std::make_unique<Threshold<WarningObject>>(bus, objPath.c_str());
646
Tao Lin91799db2022-07-27 21:02:20 +0800647 if (threshold.contains("WarningHigh"))
648 {
649 warningIface->setEntityInterfaceHigh(
650 threshold.value("WarningHighDirection", ""));
651 if (DEBUG)
652 {
653 debug("Sensor Threshold:{NAME} = intf:{INTF}", "NAME", objPath,
654 "INTF", threshold.value("WarningHighDirection", ""));
655 }
656 }
657 if (threshold.contains("WarningLow"))
658 {
659 warningIface->setEntityInterfaceLow(
660 threshold.value("WarningLowDirection", ""));
661 if (DEBUG)
662 {
663 debug("Sensor Threshold:{NAME} = intf:{INTF}", "NAME", objPath,
664 "INTF", threshold.value("WarningLowDirection", ""));
665 }
666 }
667
668 warningIface->setEntityPath(entityPath);
669 if (DEBUG)
670 {
671 debug("Sensor Threshold:{NAME} = path:{PATH}", "NAME", objPath,
672 "PATH", entityPath);
673 }
Matt Spinlera291ce12023-02-06 15:12:44 -0600674
675 warningIface->warningHigh(threshold.value(
676 "WarningHigh", std::numeric_limits<double>::quiet_NaN()));
677 warningIface->warningLow(threshold.value(
678 "WarningLow", std::numeric_limits<double>::quiet_NaN()));
679 warningIface->setHighHysteresis(
680 threshold.value("WarningHighHysteresis", defaultHysteresis));
681 warningIface->setLowHysteresis(
682 threshold.value("WarningLowHysteresis", defaultHysteresis));
Rashmica Gupta3e999192021-06-09 16:17:04 +1000683 }
684
685 if (threshold.contains("HardShutdownHigh") ||
686 threshold.contains("HardShutdownLow"))
687 {
688 hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>(
689 bus, objPath.c_str());
690
691 hardShutdownIface->hardShutdownHigh(threshold.value(
692 "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
693 hardShutdownIface->hardShutdownLow(threshold.value(
694 "HardShutdownLow", std::numeric_limits<double>::quiet_NaN()));
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000695 hardShutdownIface->setHighHysteresis(
696 threshold.value("HardShutdownHighHysteresis", defaultHysteresis));
697 hardShutdownIface->setLowHysteresis(
698 threshold.value("HardShutdownLowHysteresis", defaultHysteresis));
Rashmica Gupta3e999192021-06-09 16:17:04 +1000699 }
700
701 if (threshold.contains("SoftShutdownHigh") ||
702 threshold.contains("SoftShutdownLow"))
703 {
704 softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>(
705 bus, objPath.c_str());
706
707 softShutdownIface->softShutdownHigh(threshold.value(
708 "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
709 softShutdownIface->softShutdownLow(threshold.value(
710 "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN()));
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000711 softShutdownIface->setHighHysteresis(
712 threshold.value("SoftShutdownHighHysteresis", defaultHysteresis));
713 softShutdownIface->setLowHysteresis(
714 threshold.value("SoftShutdownLowHysteresis", defaultHysteresis));
Rashmica Gupta3e999192021-06-09 16:17:04 +1000715 }
716
717 if (threshold.contains("PerformanceLossHigh") ||
718 threshold.contains("PerformanceLossLow"))
719 {
720 perfLossIface = std::make_unique<Threshold<PerformanceLossObject>>(
721 bus, objPath.c_str());
722
723 perfLossIface->performanceLossHigh(threshold.value(
724 "PerformanceLossHigh", std::numeric_limits<double>::quiet_NaN()));
725 perfLossIface->performanceLossLow(threshold.value(
726 "PerformanceLossLow", std::numeric_limits<double>::quiet_NaN()));
Rashmica Gupta1dff7dc2021-07-27 19:43:31 +1000727 perfLossIface->setHighHysteresis(threshold.value(
728 "PerformanceLossHighHysteresis", defaultHysteresis));
729 perfLossIface->setLowHysteresis(
730 threshold.value("PerformanceLossLowHysteresis", defaultHysteresis));
Rashmica Gupta3e999192021-06-09 16:17:04 +1000731 }
732}
733
Rashmica Guptae7efe132021-07-27 19:42:11 +1000734ManagedObjectType VirtualSensors::getObjectsFromDBus()
735{
736 ManagedObjectType objects;
737
738 try
739 {
Nan Zhouf6825b92022-09-20 20:52:43 +0000740 auto method = bus.new_method_call("xyz.openbmc_project.EntityManager",
741 "/xyz/openbmc_project/inventory",
Rashmica Guptae7efe132021-07-27 19:42:11 +1000742 "org.freedesktop.DBus.ObjectManager",
743 "GetManagedObjects");
744 auto reply = bus.call(method);
745 reply.read(objects);
746 }
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500747 catch (const sdbusplus::exception_t& ex)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000748 {
749 // If entity manager isn't running yet, keep going.
750 if (std::string("org.freedesktop.DBus.Error.ServiceUnknown") !=
751 ex.name())
752 {
Matt Spinler71b9c112022-10-18 09:14:45 -0500753 error("Could not reach entity-manager: {ERROR}", "ERROR", ex);
754 throw;
Rashmica Guptae7efe132021-07-27 19:42:11 +1000755 }
756 }
757
758 return objects;
759}
760
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500761void VirtualSensors::propertiesChanged(sdbusplus::message_t& msg)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000762{
763 std::string path;
764 PropertyMap properties;
765
766 msg.read(path, properties);
767
768 /* We get multiple callbacks for one sensor. 'Type' is a required field and
769 * is a unique label so use to to only proceed once per sensor */
770 if (properties.contains("Type"))
771 {
772 if (isCalculationType(path))
773 {
774 createVirtualSensorsFromDBus(path);
775 }
776 }
777}
778
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700779/** @brief Parsing Virtual Sensor config JSON file */
Patrick Williams32dff212023-02-09 13:54:18 -0600780Json VirtualSensors::parseConfigFile()
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700781{
Patrick Williams32dff212023-02-09 13:54:18 -0600782 using path = std::filesystem::path;
783 auto configFile = []() -> path {
784 static constexpr auto name = "virtual_sensor_config.json";
785
786 for (auto pathSeg : {std::filesystem::current_path(),
787 path{"/var/lib/phosphor-virtual-sensor"},
788 path{"/usr/share/phosphor-virtual-sensor"}})
789 {
790 auto file = pathSeg / name;
791 if (std::filesystem::exists(file))
792 {
793 return file;
794 }
795 }
796 return name;
797 }();
798
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700799 std::ifstream jsonFile(configFile);
800 if (!jsonFile.is_open())
801 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500802 error("config JSON file {FILENAME} not found", "FILENAME", configFile);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000803 return {};
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700804 }
805
806 auto data = Json::parse(jsonFile, nullptr, false);
807 if (data.is_discarded())
808 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500809 error("config readings JSON parser failure with {FILENAME}", "FILENAME",
810 configFile);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700811 throw std::exception{};
812 }
813
814 return data;
815}
816
Vijay Khemkae0d371e2020-09-21 18:35:52 -0700817std::map<std::string, ValueIface::Unit> unitMap = {
818 {"temperature", ValueIface::Unit::DegreesC},
819 {"fan_tach", ValueIface::Unit::RPMS},
820 {"voltage", ValueIface::Unit::Volts},
821 {"altitude", ValueIface::Unit::Meters},
822 {"current", ValueIface::Unit::Amperes},
823 {"power", ValueIface::Unit::Watts},
824 {"energy", ValueIface::Unit::Joules},
Kumar Thangavel2b56ddb2021-01-13 20:16:11 +0530825 {"utilization", ValueIface::Unit::Percent},
Rashmica Gupta4ac7a7f2021-07-08 12:30:50 +1000826 {"airflow", ValueIface::Unit::CFM},
827 {"pressure", ValueIface::Unit::Pascals}};
Vijay Khemkae0d371e2020-09-21 18:35:52 -0700828
Rashmica Guptae7efe132021-07-27 19:42:11 +1000829const std::string getSensorTypeFromUnit(const std::string& unit)
830{
831 std::string unitPrefix = "xyz.openbmc_project.Sensor.Value.Unit.";
832 for (auto [type, unitObj] : unitMap)
833 {
834 auto unitPath = ValueIface::convertUnitToString(unitObj);
835 if (unitPath == (unitPrefix + unit))
836 {
837 return type;
838 }
839 }
840 return "";
841}
842
843void VirtualSensors::setupMatches()
844{
845 /* Already setup */
846 if (!this->matches.empty())
847 {
848 return;
849 }
850
851 /* Setup matches */
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500852 auto eventHandler = [this](sdbusplus::message_t& message) {
Rashmica Guptae7efe132021-07-27 19:42:11 +1000853 if (message.is_method_error())
854 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500855 error("Callback method error");
Rashmica Guptae7efe132021-07-27 19:42:11 +1000856 return;
857 }
858 this->propertiesChanged(message);
859 };
860
861 for (const char* iface : calculationIfaces)
862 {
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500863 auto match = std::make_unique<sdbusplus::bus::match_t>(
Rashmica Guptae7efe132021-07-27 19:42:11 +1000864 bus,
865 sdbusplus::bus::match::rules::propertiesChangedNamespace(
866 "/xyz/openbmc_project/inventory", iface),
867 eventHandler);
868 this->matches.emplace_back(std::move(match));
869 }
870}
871
872void VirtualSensors::createVirtualSensorsFromDBus(
873 const std::string& calculationIface)
874{
875 if (calculationIface.empty())
876 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500877 error("No calculation type supplied");
Rashmica Guptae7efe132021-07-27 19:42:11 +1000878 return;
879 }
880 auto objects = getObjectsFromDBus();
881
882 /* Get virtual sensors config data */
883 for (const auto& [path, interfaceMap] : objects)
884 {
Rashmica Guptae7efe132021-07-27 19:42:11 +1000885 /* Find Virtual Sensor interfaces */
George Liu2db8d412023-08-21 16:41:04 +0800886 auto intfIter = interfaceMap.find(calculationIface);
887 if (intfIter == interfaceMap.end())
Rashmica Guptae7efe132021-07-27 19:42:11 +1000888 {
889 continue;
890 }
George Liu2db8d412023-08-21 16:41:04 +0800891
892 std::string name = path.filename();
Rashmica Guptae7efe132021-07-27 19:42:11 +1000893 if (name.empty())
894 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500895 error("Virtual Sensor name not found in entity manager config");
Rashmica Guptae7efe132021-07-27 19:42:11 +1000896 continue;
897 }
898 if (virtualSensorsMap.contains(name))
899 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500900 error("A virtual sensor named {NAME} already exists", "NAME", name);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000901 continue;
902 }
903
904 /* Extract the virtual sensor type as we need this to initialize the
905 * sensor */
George Liu2db8d412023-08-21 16:41:04 +0800906 std::string sensorType, sensorUnit;
907 auto propertyMap = intfIter->second;
908 auto proIter = propertyMap.find("Units");
909 if (proIter != propertyMap.end())
Rashmica Guptae7efe132021-07-27 19:42:11 +1000910 {
George Liu2db8d412023-08-21 16:41:04 +0800911 sensorUnit = std::get<std::string>(proIter->second);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000912 }
913 sensorType = getSensorTypeFromUnit(sensorUnit);
914 if (sensorType.empty())
915 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500916 error("Sensor unit type {TYPE} is not supported", "TYPE",
917 sensorUnit);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000918 continue;
919 }
920
921 try
922 {
George Liu2db8d412023-08-21 16:41:04 +0800923 auto objpath = static_cast<std::string>(path);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000924 auto virtObjPath = sensorDbusPath + sensorType + "/" + name;
925
926 auto virtualSensorPtr = std::make_unique<VirtualSensor>(
927 bus, virtObjPath.c_str(), interfaceMap, name, sensorType,
Tao Lindc777012022-07-27 20:41:46 +0800928 calculationIface, objpath);
Patrick Williams82b39c62021-07-28 16:22:27 -0500929 info("Added a new virtual sensor: {NAME} {TYPE}", "NAME", name,
930 "TYPE", sensorType);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000931 virtualSensorPtr->updateVirtualSensor();
932
933 /* Initialize unit value for virtual sensor */
934 virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
935 virtualSensorPtr->emit_object_added();
936
937 virtualSensorsMap.emplace(name, std::move(virtualSensorPtr));
938
939 /* Setup match for interfaces removed */
Patrick Williamsae10c522023-10-20 11:19:44 -0500940 auto intfRemoved = [this, objpath,
941 name](sdbusplus::message_t& message) {
Rashmica Guptae7efe132021-07-27 19:42:11 +1000942 if (!virtualSensorsMap.contains(name))
943 {
944 return;
945 }
946 sdbusplus::message::object_path path;
947 message.read(path);
948 if (static_cast<const std::string&>(path) == objpath)
949 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500950 info("Removed a virtual sensor: {NAME}", "NAME", name);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000951 virtualSensorsMap.erase(name);
952 }
953 };
Patrick Williams8e11ccc2022-07-22 19:26:57 -0500954 auto matchOnRemove = std::make_unique<sdbusplus::bus::match_t>(
Rashmica Guptae7efe132021-07-27 19:42:11 +1000955 bus,
956 sdbusplus::bus::match::rules::interfacesRemoved() +
957 sdbusplus::bus::match::rules::argNpath(0, objpath),
958 intfRemoved);
959 /* TODO: slight race condition here. Check that the config still
960 * exists */
961 this->matches.emplace_back(std::move(matchOnRemove));
962 }
Patrick Williamsdac26632021-10-06 14:38:47 -0500963 catch (const std::invalid_argument& ia)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000964 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500965 error("Failed to set up virtual sensor: {ERROR}", "ERROR", ia);
Rashmica Guptae7efe132021-07-27 19:42:11 +1000966 }
967 }
968}
969
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700970void VirtualSensors::createVirtualSensors()
971{
972 static const Json empty{};
973
Patrick Williams32dff212023-02-09 13:54:18 -0600974 auto data = parseConfigFile();
Rashmica Guptae7efe132021-07-27 19:42:11 +1000975
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700976 // print values
977 if (DEBUG)
Rashmica Guptae7efe132021-07-27 19:42:11 +1000978 {
Patrick Williamsfbd71452021-08-30 06:59:46 -0500979 debug("JSON: {JSON}", "JSON", data.dump());
Rashmica Guptae7efe132021-07-27 19:42:11 +1000980 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700981
982 /* Get virtual sensors config data */
983 for (const auto& j : data)
984 {
985 auto desc = j.value("Desc", empty);
986 if (!desc.empty())
987 {
Rashmica Guptae7efe132021-07-27 19:42:11 +1000988 if (desc.value("Config", "") == "D-Bus")
989 {
990 /* Look on D-Bus for a virtual sensor config. Set up matches
991 * first because the configs may not be on D-Bus yet and we
992 * don't want to miss them */
993 setupMatches();
994
995 if (desc.contains("Type"))
996 {
Patrick Williams82b39c62021-07-28 16:22:27 -0500997 auto type = desc.value("Type", "");
998 auto path = "xyz.openbmc_project.Configuration." + type;
999
Rashmica Guptae7efe132021-07-27 19:42:11 +10001000 if (!isCalculationType(path))
1001 {
Patrick Williams82b39c62021-07-28 16:22:27 -05001002 error("Invalid calculation type {TYPE} supplied.",
1003 "TYPE", type);
Rashmica Guptae7efe132021-07-27 19:42:11 +10001004 continue;
1005 }
1006 createVirtualSensorsFromDBus(path);
1007 }
1008 continue;
1009 }
1010
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001011 std::string sensorType = desc.value("SensorType", "");
1012 std::string name = desc.value("Name", "");
Rashmica Gupta665a0a22021-06-30 11:35:28 +10001013 std::replace(name.begin(), name.end(), ' ', '_');
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001014
1015 if (!name.empty() && !sensorType.empty())
1016 {
Vijay Khemkae0d371e2020-09-21 18:35:52 -07001017 if (unitMap.find(sensorType) == unitMap.end())
1018 {
Patrick Williams82b39c62021-07-28 16:22:27 -05001019 error("Sensor type {TYPE} is not supported", "TYPE",
1020 sensorType);
Vijay Khemkae0d371e2020-09-21 18:35:52 -07001021 }
1022 else
1023 {
Rashmica Gupta67d8b9d2021-06-30 11:41:14 +10001024 if (virtualSensorsMap.find(name) != virtualSensorsMap.end())
1025 {
Patrick Williams82b39c62021-07-28 16:22:27 -05001026 error("A virtual sensor named {NAME} already exists",
1027 "NAME", name);
Rashmica Gupta67d8b9d2021-06-30 11:41:14 +10001028 continue;
1029 }
Rashmica Gupta862c3d12021-08-06 12:19:31 +10001030 auto objPath = sensorDbusPath + sensorType + "/" + name;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001031
Vijay Khemkae0d371e2020-09-21 18:35:52 -07001032 auto virtualSensorPtr = std::make_unique<VirtualSensor>(
1033 bus, objPath.c_str(), j, name);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001034
Patrick Williams82b39c62021-07-28 16:22:27 -05001035 info("Added a new virtual sensor: {NAME}", "NAME", name);
Vijay Khemkae0d371e2020-09-21 18:35:52 -07001036 virtualSensorPtr->updateVirtualSensor();
1037
1038 /* Initialize unit value for virtual sensor */
1039 virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
Rashmica Guptaa2fa63a2021-08-06 12:21:13 +10001040 virtualSensorPtr->emit_object_added();
Vijay Khemkae0d371e2020-09-21 18:35:52 -07001041
1042 virtualSensorsMap.emplace(std::move(name),
1043 std::move(virtualSensorPtr));
1044 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001045 }
1046 else
1047 {
Patrick Williams82b39c62021-07-28 16:22:27 -05001048 error(
1049 "Sensor type ({TYPE}) or name ({NAME}) not found in config file",
1050 "NAME", name, "TYPE", sensorType);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001051 }
1052 }
1053 else
1054 {
Patrick Williams82b39c62021-07-28 16:22:27 -05001055 error("Descriptor for new virtual sensor not found in config file");
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001056 }
1057 }
1058}
1059
1060} // namespace virtualSensor
1061} // namespace phosphor
1062
1063/**
1064 * @brief Main
1065 */
1066int main()
1067{
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001068 // Get a handle to system dbus
1069 auto bus = sdbusplus::bus::new_default();
1070
Matt Spinler6c19e7d2021-01-12 16:26:45 -06001071 // Add the ObjectManager interface
Ed Tanousf7ec40a2022-10-04 17:39:40 -07001072 sdbusplus::server::manager_t objManager(bus,
1073 "/xyz/openbmc_project/sensors");
Matt Spinler6c19e7d2021-01-12 16:26:45 -06001074
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001075 // Create an virtual sensors object
1076 phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
1077
1078 // Request service bus name
George Liu94921492023-08-21 16:18:14 +08001079 bus.request_name("xyz.openbmc_project.VirtualSensor");
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001080
Patrick Williamse6672392022-09-02 09:03:24 -05001081 // Run the dbus loop.
1082 bus.process_loop();
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001083
1084 return 0;
1085}