1abcc94faSVijay Khemka #include "virtualSensor.hpp"
2abcc94faSVijay Khemka 
3abcc94faSVijay Khemka #include "config.hpp"
4abcc94faSVijay Khemka 
5ddc6dcd6SMatt Spinler #include <fmt/format.h>
6ddc6dcd6SMatt Spinler 
7abcc94faSVijay Khemka #include <phosphor-logging/log.hpp>
8abcc94faSVijay Khemka #include <sdeventplus/event.hpp>
9abcc94faSVijay Khemka 
10abcc94faSVijay Khemka #include <fstream>
11abcc94faSVijay Khemka #include <iostream>
12abcc94faSVijay Khemka 
13abcc94faSVijay Khemka static constexpr bool DEBUG = false;
14abcc94faSVijay Khemka static constexpr auto busName = "xyz.openbmc_project.VirtualSensor";
15abcc94faSVijay Khemka static constexpr auto sensorDbusPath = "/xyz/openbmc_project/sensors/";
16abcc94faSVijay Khemka 
17abcc94faSVijay Khemka using namespace phosphor::logging;
18abcc94faSVijay Khemka 
1951f898e2SVijay Khemka int handleDbusSignal(sd_bus_message* msg, void* usrData, sd_bus_error*)
2051f898e2SVijay Khemka {
2151f898e2SVijay Khemka     if (usrData == nullptr)
2251f898e2SVijay Khemka     {
2351f898e2SVijay Khemka         throw std::runtime_error("Invalid match");
2451f898e2SVijay Khemka     }
2551f898e2SVijay Khemka 
2651f898e2SVijay Khemka     auto sdbpMsg = sdbusplus::message::message(msg);
2751f898e2SVijay Khemka     std::string msgIfce;
2851f898e2SVijay Khemka     std::map<std::string, std::variant<int64_t, double, bool>> msgData;
2951f898e2SVijay Khemka 
3051f898e2SVijay Khemka     sdbpMsg.read(msgIfce, msgData);
3151f898e2SVijay Khemka 
3251f898e2SVijay Khemka     if (msgData.find("Value") != msgData.end())
3351f898e2SVijay Khemka     {
3451f898e2SVijay Khemka         using namespace phosphor::virtualSensor;
3551f898e2SVijay Khemka         VirtualSensor* obj = static_cast<VirtualSensor*>(usrData);
3651f898e2SVijay Khemka         // TODO(openbmc/phosphor-virtual-sensor#1): updateVirtualSensor should
3751f898e2SVijay Khemka         // be changed to take the information we got from the signal, to avoid
3851f898e2SVijay Khemka         // having to do numerous dbus queries.
3951f898e2SVijay Khemka         obj->updateVirtualSensor();
4051f898e2SVijay Khemka     }
4151f898e2SVijay Khemka     return 0;
4251f898e2SVijay Khemka }
4351f898e2SVijay Khemka 
44abcc94faSVijay Khemka namespace phosphor
45abcc94faSVijay Khemka {
46abcc94faSVijay Khemka namespace virtualSensor
47abcc94faSVijay Khemka {
48abcc94faSVijay Khemka 
49abcc94faSVijay Khemka void printParams(const VirtualSensor::ParamMap& paramMap)
50abcc94faSVijay Khemka {
51abcc94faSVijay Khemka     for (const auto& p : paramMap)
52abcc94faSVijay Khemka     {
53abcc94faSVijay Khemka         const auto& p1 = p.first;
54abcc94faSVijay Khemka         const auto& p2 = p.second;
55abcc94faSVijay Khemka         auto val = p2->getParamValue();
56abcc94faSVijay Khemka         std::cout << p1 << " = " << val << "\n";
57abcc94faSVijay Khemka     }
58abcc94faSVijay Khemka }
59abcc94faSVijay Khemka 
60abcc94faSVijay Khemka double SensorParam::getParamValue()
61abcc94faSVijay Khemka {
62abcc94faSVijay Khemka     switch (paramType)
63abcc94faSVijay Khemka     {
64abcc94faSVijay Khemka         case constParam:
65abcc94faSVijay Khemka             return value;
66abcc94faSVijay Khemka             break;
677452a867SVijay Khemka         case dbusParam:
687452a867SVijay Khemka             return dbusSensor->getSensorValue();
697452a867SVijay Khemka             break;
70abcc94faSVijay Khemka         default:
71abcc94faSVijay Khemka             throw std::invalid_argument("param type not supported");
72abcc94faSVijay Khemka     }
73abcc94faSVijay Khemka }
74abcc94faSVijay Khemka 
75ce675228SMatt Spinler void VirtualSensor::initVirtualSensor(const Json& sensorConfig,
76ce675228SMatt Spinler                                       const std::string& objPath)
77abcc94faSVijay Khemka {
78abcc94faSVijay Khemka 
79abcc94faSVijay Khemka     static const Json empty{};
80abcc94faSVijay Khemka 
81abcc94faSVijay Khemka     /* Get threshold values if defined in config */
82abcc94faSVijay Khemka     auto threshold = sensorConfig.value("Threshold", empty);
83abcc94faSVijay Khemka     if (!threshold.empty())
84abcc94faSVijay Khemka     {
85f15189e3SMatt Spinler         // Only create the threshold interfaces if
86ce675228SMatt Spinler         // at least one of their values is present.
87f15189e3SMatt Spinler 
88f15189e3SMatt Spinler         if (threshold.contains("CriticalHigh") ||
89f15189e3SMatt Spinler             threshold.contains("CriticalLow"))
90f15189e3SMatt Spinler         {
91fdb826d5SPatrick Williams             criticalIface = std::make_unique<Threshold<CriticalObject>>(
92fdb826d5SPatrick Williams                 bus, objPath.c_str());
93f15189e3SMatt Spinler 
94f15189e3SMatt Spinler             criticalIface->criticalHigh(threshold.value(
95f15189e3SMatt Spinler                 "CriticalHigh", std::numeric_limits<double>::quiet_NaN()));
96f15189e3SMatt Spinler             criticalIface->criticalLow(threshold.value(
97f15189e3SMatt Spinler                 "CriticalLow", std::numeric_limits<double>::quiet_NaN()));
98f15189e3SMatt Spinler         }
99f15189e3SMatt Spinler 
100f15189e3SMatt Spinler         if (threshold.contains("WarningHigh") ||
101f15189e3SMatt Spinler             threshold.contains("WarningLow"))
102f15189e3SMatt Spinler         {
103fdb826d5SPatrick Williams             warningIface = std::make_unique<Threshold<WarningObject>>(
104fdb826d5SPatrick Williams                 bus, objPath.c_str());
105f15189e3SMatt Spinler 
106f15189e3SMatt Spinler             warningIface->warningHigh(threshold.value(
107f15189e3SMatt Spinler                 "WarningHigh", std::numeric_limits<double>::quiet_NaN()));
108f15189e3SMatt Spinler             warningIface->warningLow(threshold.value(
109f15189e3SMatt Spinler                 "WarningLow", std::numeric_limits<double>::quiet_NaN()));
110f15189e3SMatt Spinler         }
111f15189e3SMatt Spinler 
112ce675228SMatt Spinler         if (threshold.contains("HardShutdownHigh") ||
113ce675228SMatt Spinler             threshold.contains("HardShutdownLow"))
114ce675228SMatt Spinler         {
115fdb826d5SPatrick Williams             hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>(
116fdb826d5SPatrick Williams                 bus, objPath.c_str());
117ce675228SMatt Spinler 
118ce675228SMatt Spinler             hardShutdownIface->hardShutdownHigh(threshold.value(
119ce675228SMatt Spinler                 "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
120ce675228SMatt Spinler             hardShutdownIface->hardShutdownLow(threshold.value(
121ce675228SMatt Spinler                 "HardShutdownLow", std::numeric_limits<double>::quiet_NaN()));
122ce675228SMatt Spinler         }
123ce675228SMatt Spinler 
124ce675228SMatt Spinler         if (threshold.contains("SoftShutdownHigh") ||
125ce675228SMatt Spinler             threshold.contains("SoftShutdownLow"))
126ce675228SMatt Spinler         {
127fdb826d5SPatrick Williams             softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>(
128fdb826d5SPatrick Williams                 bus, objPath.c_str());
129ce675228SMatt Spinler 
130ce675228SMatt Spinler             softShutdownIface->softShutdownHigh(threshold.value(
131ce675228SMatt Spinler                 "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
132ce675228SMatt Spinler             softShutdownIface->softShutdownLow(threshold.value(
133ce675228SMatt Spinler                 "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN()));
134ce675228SMatt Spinler         }
135b306b03dSMatt Spinler 
136b306b03dSMatt Spinler         if (threshold.contains("PerformanceLossHigh") ||
137b306b03dSMatt Spinler             threshold.contains("PerformanceLossLow"))
138b306b03dSMatt Spinler         {
139b306b03dSMatt Spinler             perfLossIface = std::make_unique<Threshold<PerformanceLossObject>>(
140b306b03dSMatt Spinler                 bus, objPath.c_str());
141b306b03dSMatt Spinler 
142b306b03dSMatt Spinler             perfLossIface->performanceLossHigh(
143b306b03dSMatt Spinler                 threshold.value("PerformanceLossHigh",
144b306b03dSMatt Spinler                                 std::numeric_limits<double>::quiet_NaN()));
145b306b03dSMatt Spinler             perfLossIface->performanceLossLow(
146b306b03dSMatt Spinler                 threshold.value("PerformanceLossLow",
147b306b03dSMatt Spinler                                 std::numeric_limits<double>::quiet_NaN()));
148b306b03dSMatt Spinler         }
149c62a5548SVijay Khemka     }
150abcc94faSVijay Khemka 
151f6443742SHarvey Wu     /* Get MaxValue, MinValue setting if defined in config */
152f6443742SHarvey Wu     auto confDesc = sensorConfig.value("Desc", empty);
153f6443742SHarvey Wu     if (auto maxConf = confDesc.find("MaxValue");
154f6443742SHarvey Wu         maxConf != confDesc.end() && maxConf->is_number())
155f6443742SHarvey Wu     {
156f6443742SHarvey Wu         ValueIface::maxValue(maxConf->get<double>());
157f6443742SHarvey Wu     }
158f6443742SHarvey Wu     if (auto minConf = confDesc.find("MinValue");
159f6443742SHarvey Wu         minConf != confDesc.end() && minConf->is_number())
160f6443742SHarvey Wu     {
161f6443742SHarvey Wu         ValueIface::minValue(minConf->get<double>());
162f6443742SHarvey Wu     }
163f6443742SHarvey Wu 
164abcc94faSVijay Khemka     /* Get expression string */
165abcc94faSVijay Khemka     exprStr = sensorConfig.value("Expression", "");
166abcc94faSVijay Khemka 
167abcc94faSVijay Khemka     /* Get all the parameter listed in configuration */
168abcc94faSVijay Khemka     auto params = sensorConfig.value("Params", empty);
169abcc94faSVijay Khemka 
170abcc94faSVijay Khemka     /* Check for constant parameter */
171abcc94faSVijay Khemka     const auto& consParams = params.value("ConstParam", empty);
172abcc94faSVijay Khemka     if (!consParams.empty())
173abcc94faSVijay Khemka     {
174abcc94faSVijay Khemka         for (auto& j : consParams)
175abcc94faSVijay Khemka         {
176abcc94faSVijay Khemka             if (j.find("ParamName") != j.end())
177abcc94faSVijay Khemka             {
178abcc94faSVijay Khemka                 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
1793ed9a516SVijay Khemka                 std::string name = j["ParamName"];
1803ed9a516SVijay Khemka                 symbols.create_variable(name);
1813ed9a516SVijay Khemka                 paramMap.emplace(std::move(name), std::move(paramPtr));
182abcc94faSVijay Khemka             }
183abcc94faSVijay Khemka             else
184abcc94faSVijay Khemka             {
185abcc94faSVijay Khemka                 /* Invalid configuration */
186abcc94faSVijay Khemka                 throw std::invalid_argument(
187abcc94faSVijay Khemka                     "ParamName not found in configuration");
188abcc94faSVijay Khemka             }
189abcc94faSVijay Khemka         }
190abcc94faSVijay Khemka     }
191abcc94faSVijay Khemka 
1927452a867SVijay Khemka     /* Check for dbus parameter */
1937452a867SVijay Khemka     auto dbusParams = params.value("DbusParam", empty);
1947452a867SVijay Khemka     if (!dbusParams.empty())
1957452a867SVijay Khemka     {
1967452a867SVijay Khemka         for (auto& j : dbusParams)
1977452a867SVijay Khemka         {
1987452a867SVijay Khemka             /* Get parameter dbus sensor descriptor */
1997452a867SVijay Khemka             auto desc = j.value("Desc", empty);
2007452a867SVijay Khemka             if ((!desc.empty()) && (j.find("ParamName") != j.end()))
2017452a867SVijay Khemka             {
2027452a867SVijay Khemka                 std::string sensorType = desc.value("SensorType", "");
2037452a867SVijay Khemka                 std::string name = desc.value("Name", "");
2047452a867SVijay Khemka 
2057452a867SVijay Khemka                 if (!sensorType.empty() && !name.empty())
2067452a867SVijay Khemka                 {
2077452a867SVijay Khemka                     std::string objPath(sensorDbusPath);
2087452a867SVijay Khemka                     objPath += sensorType + "/" + name;
2097452a867SVijay Khemka 
21051f898e2SVijay Khemka                     auto paramPtr =
21151f898e2SVijay Khemka                         std::make_unique<SensorParam>(bus, objPath, this);
2123ed9a516SVijay Khemka                     std::string name = j["ParamName"];
2133ed9a516SVijay Khemka                     symbols.create_variable(name);
2143ed9a516SVijay Khemka                     paramMap.emplace(std::move(name), std::move(paramPtr));
2157452a867SVijay Khemka                 }
2167452a867SVijay Khemka             }
2177452a867SVijay Khemka         }
2187452a867SVijay Khemka     }
219abcc94faSVijay Khemka 
2203ed9a516SVijay Khemka     symbols.add_constants();
2219f1ef4f5SMatt Spinler     symbols.add_package(vecopsPackage);
2223ed9a516SVijay Khemka     expression.register_symbol_table(symbols);
2233ed9a516SVijay Khemka 
2243ed9a516SVijay Khemka     /* parser from exprtk */
2253ed9a516SVijay Khemka     exprtk::parser<double> parser{};
226ddc6dcd6SMatt Spinler     if (!parser.compile(exprStr, expression))
227ddc6dcd6SMatt Spinler     {
228ddc6dcd6SMatt Spinler         log<level::ERR>("Expression compilation failed");
229ddc6dcd6SMatt Spinler 
230ddc6dcd6SMatt Spinler         for (std::size_t i = 0; i < parser.error_count(); ++i)
231ddc6dcd6SMatt Spinler         {
232ddc6dcd6SMatt Spinler             auto error = parser.get_error(i);
233ddc6dcd6SMatt Spinler 
234ddc6dcd6SMatt Spinler             log<level::ERR>(
235ddc6dcd6SMatt Spinler                 fmt::format(
236ddc6dcd6SMatt Spinler                     "Position: {} Type: {} Message: {}", error.token.position,
237ddc6dcd6SMatt Spinler                     exprtk::parser_error::to_str(error.mode), error.diagnostic)
238ddc6dcd6SMatt Spinler                     .c_str());
239ddc6dcd6SMatt Spinler         }
240ddc6dcd6SMatt Spinler         throw std::runtime_error("Expression compilation failed");
241ddc6dcd6SMatt Spinler     }
2423ed9a516SVijay Khemka 
243abcc94faSVijay Khemka     /* Print all parameters for debug purpose only */
244abcc94faSVijay Khemka     if (DEBUG)
245abcc94faSVijay Khemka         printParams(paramMap);
246abcc94faSVijay Khemka }
247abcc94faSVijay Khemka 
248abcc94faSVijay Khemka void VirtualSensor::setSensorValue(double value)
249abcc94faSVijay Khemka {
250*543bf668SPatrick Williams     value = std::clamp(value, ValueIface::minValue(), ValueIface::maxValue());
251abcc94faSVijay Khemka     ValueIface::value(value);
252abcc94faSVijay Khemka }
253abcc94faSVijay Khemka 
254abcc94faSVijay Khemka void VirtualSensor::updateVirtualSensor()
2553ed9a516SVijay Khemka {
2563ed9a516SVijay Khemka     for (auto& param : paramMap)
2573ed9a516SVijay Khemka     {
2583ed9a516SVijay Khemka         auto& name = param.first;
2593ed9a516SVijay Khemka         auto& data = param.second;
2603ed9a516SVijay Khemka         if (auto var = symbols.get_variable(name))
2613ed9a516SVijay Khemka         {
2623ed9a516SVijay Khemka             var->ref() = data->getParamValue();
2633ed9a516SVijay Khemka         }
2643ed9a516SVijay Khemka         else
2653ed9a516SVijay Khemka         {
2663ed9a516SVijay Khemka             /* Invalid parameter */
2673ed9a516SVijay Khemka             throw std::invalid_argument("ParamName not found in symbols");
2683ed9a516SVijay Khemka         }
2693ed9a516SVijay Khemka     }
2703ed9a516SVijay Khemka     double val = expression.value();
27132a7156bSVijay Khemka 
27232a7156bSVijay Khemka     /* Set sensor value to dbus interface */
2733ed9a516SVijay Khemka     setSensorValue(val);
27432a7156bSVijay Khemka 
2753ed9a516SVijay Khemka     if (DEBUG)
2763ed9a516SVijay Khemka         std::cout << "Sensor value is " << val << "\n";
27732a7156bSVijay Khemka 
2788f5e6119SMatt Spinler     /* Check sensor thresholds and log required message */
279b306b03dSMatt Spinler     checkThresholds(val, perfLossIface);
280fdb826d5SPatrick Williams     checkThresholds(val, warningIface);
281fdb826d5SPatrick Williams     checkThresholds(val, criticalIface);
282fdb826d5SPatrick Williams     checkThresholds(val, softShutdownIface);
283fdb826d5SPatrick Williams     checkThresholds(val, hardShutdownIface);
2843ed9a516SVijay Khemka }
285abcc94faSVijay Khemka 
286abcc94faSVijay Khemka /** @brief Parsing Virtual Sensor config JSON file  */
287abcc94faSVijay Khemka Json VirtualSensors::parseConfigFile(const std::string configFile)
288abcc94faSVijay Khemka {
289abcc94faSVijay Khemka     std::ifstream jsonFile(configFile);
290abcc94faSVijay Khemka     if (!jsonFile.is_open())
291abcc94faSVijay Khemka     {
292abcc94faSVijay Khemka         log<level::ERR>("config JSON file not found",
293abcc94faSVijay Khemka                         entry("FILENAME = %s", configFile.c_str()));
294abcc94faSVijay Khemka         throw std::exception{};
295abcc94faSVijay Khemka     }
296abcc94faSVijay Khemka 
297abcc94faSVijay Khemka     auto data = Json::parse(jsonFile, nullptr, false);
298abcc94faSVijay Khemka     if (data.is_discarded())
299abcc94faSVijay Khemka     {
300abcc94faSVijay Khemka         log<level::ERR>("config readings JSON parser failure",
301abcc94faSVijay Khemka                         entry("FILENAME = %s", configFile.c_str()));
302abcc94faSVijay Khemka         throw std::exception{};
303abcc94faSVijay Khemka     }
304abcc94faSVijay Khemka 
305abcc94faSVijay Khemka     return data;
306abcc94faSVijay Khemka }
307abcc94faSVijay Khemka 
308e0d371e4SVijay Khemka std::map<std::string, ValueIface::Unit> unitMap = {
309e0d371e4SVijay Khemka     {"temperature", ValueIface::Unit::DegreesC},
310e0d371e4SVijay Khemka     {"fan_tach", ValueIface::Unit::RPMS},
311e0d371e4SVijay Khemka     {"voltage", ValueIface::Unit::Volts},
312e0d371e4SVijay Khemka     {"altitude", ValueIface::Unit::Meters},
313e0d371e4SVijay Khemka     {"current", ValueIface::Unit::Amperes},
314e0d371e4SVijay Khemka     {"power", ValueIface::Unit::Watts},
315e0d371e4SVijay Khemka     {"energy", ValueIface::Unit::Joules},
3162b56ddb3SKumar Thangavel     {"utilization", ValueIface::Unit::Percent},
3172b56ddb3SKumar Thangavel     {"airflow", ValueIface::Unit::CFM}};
318e0d371e4SVijay Khemka 
319abcc94faSVijay Khemka void VirtualSensors::createVirtualSensors()
320abcc94faSVijay Khemka {
321abcc94faSVijay Khemka     static const Json empty{};
322abcc94faSVijay Khemka 
323abcc94faSVijay Khemka     auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
324abcc94faSVijay Khemka     // print values
325abcc94faSVijay Khemka     if (DEBUG)
326abcc94faSVijay Khemka         std::cout << "Config json data:\n" << data << "\n\n";
327abcc94faSVijay Khemka 
328abcc94faSVijay Khemka     /* Get virtual sensors  config data */
329abcc94faSVijay Khemka     for (const auto& j : data)
330abcc94faSVijay Khemka     {
331abcc94faSVijay Khemka         auto desc = j.value("Desc", empty);
332abcc94faSVijay Khemka         if (!desc.empty())
333abcc94faSVijay Khemka         {
334abcc94faSVijay Khemka             std::string sensorType = desc.value("SensorType", "");
335abcc94faSVijay Khemka             std::string name = desc.value("Name", "");
336abcc94faSVijay Khemka 
337abcc94faSVijay Khemka             if (!name.empty() && !sensorType.empty())
338abcc94faSVijay Khemka             {
339e0d371e4SVijay Khemka                 if (unitMap.find(sensorType) == unitMap.end())
340e0d371e4SVijay Khemka                 {
341e0d371e4SVijay Khemka                     log<level::ERR>("Sensor type is not supported",
342e0d371e4SVijay Khemka                                     entry("TYPE = %s", sensorType.c_str()));
343e0d371e4SVijay Khemka                 }
344e0d371e4SVijay Khemka                 else
345e0d371e4SVijay Khemka                 {
346abcc94faSVijay Khemka                     std::string objPath(sensorDbusPath);
347abcc94faSVijay Khemka                     objPath += sensorType + "/" + name;
348abcc94faSVijay Khemka 
34932a7156bSVijay Khemka                     auto virtualSensorPtr = std::make_unique<VirtualSensor>(
35032a7156bSVijay Khemka                         bus, objPath.c_str(), j, name);
351abcc94faSVijay Khemka 
352abcc94faSVijay Khemka                     log<level::INFO>("Added a new virtual sensor",
353abcc94faSVijay Khemka                                      entry("NAME = %s", name.c_str()));
3543ed9a516SVijay Khemka                     virtualSensorPtr->updateVirtualSensor();
355e0d371e4SVijay Khemka 
356e0d371e4SVijay Khemka                     /* Initialize unit value for virtual sensor */
357e0d371e4SVijay Khemka                     virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
358e0d371e4SVijay Khemka 
3593ed9a516SVijay Khemka                     virtualSensorsMap.emplace(std::move(name),
3603ed9a516SVijay Khemka                                               std::move(virtualSensorPtr));
361abcc94faSVijay Khemka                 }
362e0d371e4SVijay Khemka             }
363abcc94faSVijay Khemka             else
364abcc94faSVijay Khemka             {
365abcc94faSVijay Khemka                 log<level::ERR>("Sensor type or name not found in config file");
366abcc94faSVijay Khemka             }
367abcc94faSVijay Khemka         }
368abcc94faSVijay Khemka         else
369abcc94faSVijay Khemka         {
370abcc94faSVijay Khemka             log<level::ERR>(
371abcc94faSVijay Khemka                 "Descriptor for new virtual sensor not found in config file");
372abcc94faSVijay Khemka         }
373abcc94faSVijay Khemka     }
374abcc94faSVijay Khemka }
375abcc94faSVijay Khemka 
376abcc94faSVijay Khemka } // namespace virtualSensor
377abcc94faSVijay Khemka } // namespace phosphor
378abcc94faSVijay Khemka 
379abcc94faSVijay Khemka /**
380abcc94faSVijay Khemka  * @brief Main
381abcc94faSVijay Khemka  */
382abcc94faSVijay Khemka int main()
383abcc94faSVijay Khemka {
384abcc94faSVijay Khemka 
385abcc94faSVijay Khemka     // Get a default event loop
386abcc94faSVijay Khemka     auto event = sdeventplus::Event::get_default();
387abcc94faSVijay Khemka 
388abcc94faSVijay Khemka     // Get a handle to system dbus
389abcc94faSVijay Khemka     auto bus = sdbusplus::bus::new_default();
390abcc94faSVijay Khemka 
3916c19e7d2SMatt Spinler     // Add the ObjectManager interface
3926c19e7d2SMatt Spinler     sdbusplus::server::manager::manager objManager(bus, "/");
3936c19e7d2SMatt Spinler 
394abcc94faSVijay Khemka     // Create an virtual sensors object
395abcc94faSVijay Khemka     phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
396abcc94faSVijay Khemka 
397abcc94faSVijay Khemka     // Request service bus name
398abcc94faSVijay Khemka     bus.request_name(busName);
399abcc94faSVijay Khemka 
400abcc94faSVijay Khemka     // Attach the bus to sd_event to service user requests
401abcc94faSVijay Khemka     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
402abcc94faSVijay Khemka     event.loop();
403abcc94faSVijay Khemka 
404abcc94faSVijay Khemka     return 0;
405abcc94faSVijay Khemka }
406