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 
75*0fcf0e1cSLei YU using AssociationList =
76*0fcf0e1cSLei YU     std::vector<std::tuple<std::string, std::string, std::string>>;
77*0fcf0e1cSLei YU 
78*0fcf0e1cSLei YU AssociationList getAssociationsFromJson(const Json& j)
79*0fcf0e1cSLei YU {
80*0fcf0e1cSLei YU     AssociationList assocs{};
81*0fcf0e1cSLei YU     try
82*0fcf0e1cSLei YU     {
83*0fcf0e1cSLei YU         j.get_to(assocs);
84*0fcf0e1cSLei YU     }
85*0fcf0e1cSLei YU     catch (const std::exception& ex)
86*0fcf0e1cSLei YU     {
87*0fcf0e1cSLei YU         log<level::ERR>("Failed to parse association",
88*0fcf0e1cSLei YU                         entry("EX=%s", ex.what()));
89*0fcf0e1cSLei YU     }
90*0fcf0e1cSLei YU     return assocs;
91*0fcf0e1cSLei YU }
92*0fcf0e1cSLei YU 
93ce675228SMatt Spinler void VirtualSensor::initVirtualSensor(const Json& sensorConfig,
94ce675228SMatt Spinler                                       const std::string& objPath)
95abcc94faSVijay Khemka {
96abcc94faSVijay Khemka 
97abcc94faSVijay Khemka     static const Json empty{};
98abcc94faSVijay Khemka 
99abcc94faSVijay Khemka     /* Get threshold values if defined in config */
100abcc94faSVijay Khemka     auto threshold = sensorConfig.value("Threshold", empty);
101abcc94faSVijay Khemka     if (!threshold.empty())
102abcc94faSVijay Khemka     {
103f15189e3SMatt Spinler         // Only create the threshold interfaces if
104ce675228SMatt Spinler         // at least one of their values is present.
105f15189e3SMatt Spinler 
106f15189e3SMatt Spinler         if (threshold.contains("CriticalHigh") ||
107f15189e3SMatt Spinler             threshold.contains("CriticalLow"))
108f15189e3SMatt Spinler         {
109fdb826d5SPatrick Williams             criticalIface = std::make_unique<Threshold<CriticalObject>>(
110fdb826d5SPatrick Williams                 bus, objPath.c_str());
111f15189e3SMatt Spinler 
112f15189e3SMatt Spinler             criticalIface->criticalHigh(threshold.value(
113f15189e3SMatt Spinler                 "CriticalHigh", std::numeric_limits<double>::quiet_NaN()));
114f15189e3SMatt Spinler             criticalIface->criticalLow(threshold.value(
115f15189e3SMatt Spinler                 "CriticalLow", std::numeric_limits<double>::quiet_NaN()));
116f15189e3SMatt Spinler         }
117f15189e3SMatt Spinler 
118f15189e3SMatt Spinler         if (threshold.contains("WarningHigh") ||
119f15189e3SMatt Spinler             threshold.contains("WarningLow"))
120f15189e3SMatt Spinler         {
121fdb826d5SPatrick Williams             warningIface = std::make_unique<Threshold<WarningObject>>(
122fdb826d5SPatrick Williams                 bus, objPath.c_str());
123f15189e3SMatt Spinler 
124f15189e3SMatt Spinler             warningIface->warningHigh(threshold.value(
125f15189e3SMatt Spinler                 "WarningHigh", std::numeric_limits<double>::quiet_NaN()));
126f15189e3SMatt Spinler             warningIface->warningLow(threshold.value(
127f15189e3SMatt Spinler                 "WarningLow", std::numeric_limits<double>::quiet_NaN()));
128f15189e3SMatt Spinler         }
129f15189e3SMatt Spinler 
130ce675228SMatt Spinler         if (threshold.contains("HardShutdownHigh") ||
131ce675228SMatt Spinler             threshold.contains("HardShutdownLow"))
132ce675228SMatt Spinler         {
133fdb826d5SPatrick Williams             hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>(
134fdb826d5SPatrick Williams                 bus, objPath.c_str());
135ce675228SMatt Spinler 
136ce675228SMatt Spinler             hardShutdownIface->hardShutdownHigh(threshold.value(
137ce675228SMatt Spinler                 "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
138ce675228SMatt Spinler             hardShutdownIface->hardShutdownLow(threshold.value(
139ce675228SMatt Spinler                 "HardShutdownLow", std::numeric_limits<double>::quiet_NaN()));
140ce675228SMatt Spinler         }
141ce675228SMatt Spinler 
142ce675228SMatt Spinler         if (threshold.contains("SoftShutdownHigh") ||
143ce675228SMatt Spinler             threshold.contains("SoftShutdownLow"))
144ce675228SMatt Spinler         {
145fdb826d5SPatrick Williams             softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>(
146fdb826d5SPatrick Williams                 bus, objPath.c_str());
147ce675228SMatt Spinler 
148ce675228SMatt Spinler             softShutdownIface->softShutdownHigh(threshold.value(
149ce675228SMatt Spinler                 "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
150ce675228SMatt Spinler             softShutdownIface->softShutdownLow(threshold.value(
151ce675228SMatt Spinler                 "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN()));
152ce675228SMatt Spinler         }
153b306b03dSMatt Spinler 
154b306b03dSMatt Spinler         if (threshold.contains("PerformanceLossHigh") ||
155b306b03dSMatt Spinler             threshold.contains("PerformanceLossLow"))
156b306b03dSMatt Spinler         {
157b306b03dSMatt Spinler             perfLossIface = std::make_unique<Threshold<PerformanceLossObject>>(
158b306b03dSMatt Spinler                 bus, objPath.c_str());
159b306b03dSMatt Spinler 
160b306b03dSMatt Spinler             perfLossIface->performanceLossHigh(
161b306b03dSMatt Spinler                 threshold.value("PerformanceLossHigh",
162b306b03dSMatt Spinler                                 std::numeric_limits<double>::quiet_NaN()));
163b306b03dSMatt Spinler             perfLossIface->performanceLossLow(
164b306b03dSMatt Spinler                 threshold.value("PerformanceLossLow",
165b306b03dSMatt Spinler                                 std::numeric_limits<double>::quiet_NaN()));
166b306b03dSMatt Spinler         }
167c62a5548SVijay Khemka     }
168abcc94faSVijay Khemka 
169f6443742SHarvey Wu     /* Get MaxValue, MinValue setting if defined in config */
170f6443742SHarvey Wu     auto confDesc = sensorConfig.value("Desc", empty);
171f6443742SHarvey Wu     if (auto maxConf = confDesc.find("MaxValue");
172f6443742SHarvey Wu         maxConf != confDesc.end() && maxConf->is_number())
173f6443742SHarvey Wu     {
174f6443742SHarvey Wu         ValueIface::maxValue(maxConf->get<double>());
175f6443742SHarvey Wu     }
176f6443742SHarvey Wu     if (auto minConf = confDesc.find("MinValue");
177f6443742SHarvey Wu         minConf != confDesc.end() && minConf->is_number())
178f6443742SHarvey Wu     {
179f6443742SHarvey Wu         ValueIface::minValue(minConf->get<double>());
180f6443742SHarvey Wu     }
181f6443742SHarvey Wu 
182*0fcf0e1cSLei YU     /* Get optional association */
183*0fcf0e1cSLei YU     auto assocJson = sensorConfig.value("Associations", empty);
184*0fcf0e1cSLei YU     if (!assocJson.empty())
185*0fcf0e1cSLei YU     {
186*0fcf0e1cSLei YU         auto assocs = getAssociationsFromJson(assocJson);
187*0fcf0e1cSLei YU         if (!assocs.empty())
188*0fcf0e1cSLei YU         {
189*0fcf0e1cSLei YU             associationIface =
190*0fcf0e1cSLei YU                 std::make_unique<AssociationObject>(bus, objPath.c_str());
191*0fcf0e1cSLei YU             associationIface->associations(assocs);
192*0fcf0e1cSLei YU         }
193*0fcf0e1cSLei YU     }
194*0fcf0e1cSLei YU 
195abcc94faSVijay Khemka     /* Get expression string */
196abcc94faSVijay Khemka     exprStr = sensorConfig.value("Expression", "");
197abcc94faSVijay Khemka 
198abcc94faSVijay Khemka     /* Get all the parameter listed in configuration */
199abcc94faSVijay Khemka     auto params = sensorConfig.value("Params", empty);
200abcc94faSVijay Khemka 
201abcc94faSVijay Khemka     /* Check for constant parameter */
202abcc94faSVijay Khemka     const auto& consParams = params.value("ConstParam", empty);
203abcc94faSVijay Khemka     if (!consParams.empty())
204abcc94faSVijay Khemka     {
205abcc94faSVijay Khemka         for (auto& j : consParams)
206abcc94faSVijay Khemka         {
207abcc94faSVijay Khemka             if (j.find("ParamName") != j.end())
208abcc94faSVijay Khemka             {
209abcc94faSVijay Khemka                 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
2103ed9a516SVijay Khemka                 std::string name = j["ParamName"];
2113ed9a516SVijay Khemka                 symbols.create_variable(name);
2123ed9a516SVijay Khemka                 paramMap.emplace(std::move(name), std::move(paramPtr));
213abcc94faSVijay Khemka             }
214abcc94faSVijay Khemka             else
215abcc94faSVijay Khemka             {
216abcc94faSVijay Khemka                 /* Invalid configuration */
217abcc94faSVijay Khemka                 throw std::invalid_argument(
218abcc94faSVijay Khemka                     "ParamName not found in configuration");
219abcc94faSVijay Khemka             }
220abcc94faSVijay Khemka         }
221abcc94faSVijay Khemka     }
222abcc94faSVijay Khemka 
2237452a867SVijay Khemka     /* Check for dbus parameter */
2247452a867SVijay Khemka     auto dbusParams = params.value("DbusParam", empty);
2257452a867SVijay Khemka     if (!dbusParams.empty())
2267452a867SVijay Khemka     {
2277452a867SVijay Khemka         for (auto& j : dbusParams)
2287452a867SVijay Khemka         {
2297452a867SVijay Khemka             /* Get parameter dbus sensor descriptor */
2307452a867SVijay Khemka             auto desc = j.value("Desc", empty);
2317452a867SVijay Khemka             if ((!desc.empty()) && (j.find("ParamName") != j.end()))
2327452a867SVijay Khemka             {
2337452a867SVijay Khemka                 std::string sensorType = desc.value("SensorType", "");
2347452a867SVijay Khemka                 std::string name = desc.value("Name", "");
2357452a867SVijay Khemka 
2367452a867SVijay Khemka                 if (!sensorType.empty() && !name.empty())
2377452a867SVijay Khemka                 {
2387452a867SVijay Khemka                     std::string objPath(sensorDbusPath);
2397452a867SVijay Khemka                     objPath += sensorType + "/" + name;
2407452a867SVijay Khemka 
24151f898e2SVijay Khemka                     auto paramPtr =
24251f898e2SVijay Khemka                         std::make_unique<SensorParam>(bus, objPath, this);
2433ed9a516SVijay Khemka                     std::string name = j["ParamName"];
2443ed9a516SVijay Khemka                     symbols.create_variable(name);
2453ed9a516SVijay Khemka                     paramMap.emplace(std::move(name), std::move(paramPtr));
2467452a867SVijay Khemka                 }
2477452a867SVijay Khemka             }
2487452a867SVijay Khemka         }
2497452a867SVijay Khemka     }
250abcc94faSVijay Khemka 
2513ed9a516SVijay Khemka     symbols.add_constants();
2529f1ef4f5SMatt Spinler     symbols.add_package(vecopsPackage);
2533ed9a516SVijay Khemka     expression.register_symbol_table(symbols);
2543ed9a516SVijay Khemka 
2553ed9a516SVijay Khemka     /* parser from exprtk */
2563ed9a516SVijay Khemka     exprtk::parser<double> parser{};
257ddc6dcd6SMatt Spinler     if (!parser.compile(exprStr, expression))
258ddc6dcd6SMatt Spinler     {
259ddc6dcd6SMatt Spinler         log<level::ERR>("Expression compilation failed");
260ddc6dcd6SMatt Spinler 
261ddc6dcd6SMatt Spinler         for (std::size_t i = 0; i < parser.error_count(); ++i)
262ddc6dcd6SMatt Spinler         {
263ddc6dcd6SMatt Spinler             auto error = parser.get_error(i);
264ddc6dcd6SMatt Spinler 
265ddc6dcd6SMatt Spinler             log<level::ERR>(
266ddc6dcd6SMatt Spinler                 fmt::format(
267ddc6dcd6SMatt Spinler                     "Position: {} Type: {} Message: {}", error.token.position,
268ddc6dcd6SMatt Spinler                     exprtk::parser_error::to_str(error.mode), error.diagnostic)
269ddc6dcd6SMatt Spinler                     .c_str());
270ddc6dcd6SMatt Spinler         }
271ddc6dcd6SMatt Spinler         throw std::runtime_error("Expression compilation failed");
272ddc6dcd6SMatt Spinler     }
2733ed9a516SVijay Khemka 
274abcc94faSVijay Khemka     /* Print all parameters for debug purpose only */
275abcc94faSVijay Khemka     if (DEBUG)
276abcc94faSVijay Khemka         printParams(paramMap);
277abcc94faSVijay Khemka }
278abcc94faSVijay Khemka 
279abcc94faSVijay Khemka void VirtualSensor::setSensorValue(double value)
280abcc94faSVijay Khemka {
281543bf668SPatrick Williams     value = std::clamp(value, ValueIface::minValue(), ValueIface::maxValue());
282abcc94faSVijay Khemka     ValueIface::value(value);
283abcc94faSVijay Khemka }
284abcc94faSVijay Khemka 
285abcc94faSVijay Khemka void VirtualSensor::updateVirtualSensor()
2863ed9a516SVijay Khemka {
2873ed9a516SVijay Khemka     for (auto& param : paramMap)
2883ed9a516SVijay Khemka     {
2893ed9a516SVijay Khemka         auto& name = param.first;
2903ed9a516SVijay Khemka         auto& data = param.second;
2913ed9a516SVijay Khemka         if (auto var = symbols.get_variable(name))
2923ed9a516SVijay Khemka         {
2933ed9a516SVijay Khemka             var->ref() = data->getParamValue();
2943ed9a516SVijay Khemka         }
2953ed9a516SVijay Khemka         else
2963ed9a516SVijay Khemka         {
2973ed9a516SVijay Khemka             /* Invalid parameter */
2983ed9a516SVijay Khemka             throw std::invalid_argument("ParamName not found in symbols");
2993ed9a516SVijay Khemka         }
3003ed9a516SVijay Khemka     }
3013ed9a516SVijay Khemka     double val = expression.value();
30232a7156bSVijay Khemka 
30332a7156bSVijay Khemka     /* Set sensor value to dbus interface */
3043ed9a516SVijay Khemka     setSensorValue(val);
30532a7156bSVijay Khemka 
3063ed9a516SVijay Khemka     if (DEBUG)
3073ed9a516SVijay Khemka         std::cout << "Sensor value is " << val << "\n";
30832a7156bSVijay Khemka 
3098f5e6119SMatt Spinler     /* Check sensor thresholds and log required message */
310b306b03dSMatt Spinler     checkThresholds(val, perfLossIface);
311fdb826d5SPatrick Williams     checkThresholds(val, warningIface);
312fdb826d5SPatrick Williams     checkThresholds(val, criticalIface);
313fdb826d5SPatrick Williams     checkThresholds(val, softShutdownIface);
314fdb826d5SPatrick Williams     checkThresholds(val, hardShutdownIface);
3153ed9a516SVijay Khemka }
316abcc94faSVijay Khemka 
317abcc94faSVijay Khemka /** @brief Parsing Virtual Sensor config JSON file  */
318abcc94faSVijay Khemka Json VirtualSensors::parseConfigFile(const std::string configFile)
319abcc94faSVijay Khemka {
320abcc94faSVijay Khemka     std::ifstream jsonFile(configFile);
321abcc94faSVijay Khemka     if (!jsonFile.is_open())
322abcc94faSVijay Khemka     {
323abcc94faSVijay Khemka         log<level::ERR>("config JSON file not found",
324abcc94faSVijay Khemka                         entry("FILENAME = %s", configFile.c_str()));
325abcc94faSVijay Khemka         throw std::exception{};
326abcc94faSVijay Khemka     }
327abcc94faSVijay Khemka 
328abcc94faSVijay Khemka     auto data = Json::parse(jsonFile, nullptr, false);
329abcc94faSVijay Khemka     if (data.is_discarded())
330abcc94faSVijay Khemka     {
331abcc94faSVijay Khemka         log<level::ERR>("config readings JSON parser failure",
332abcc94faSVijay Khemka                         entry("FILENAME = %s", configFile.c_str()));
333abcc94faSVijay Khemka         throw std::exception{};
334abcc94faSVijay Khemka     }
335abcc94faSVijay Khemka 
336abcc94faSVijay Khemka     return data;
337abcc94faSVijay Khemka }
338abcc94faSVijay Khemka 
339e0d371e4SVijay Khemka std::map<std::string, ValueIface::Unit> unitMap = {
340e0d371e4SVijay Khemka     {"temperature", ValueIface::Unit::DegreesC},
341e0d371e4SVijay Khemka     {"fan_tach", ValueIface::Unit::RPMS},
342e0d371e4SVijay Khemka     {"voltage", ValueIface::Unit::Volts},
343e0d371e4SVijay Khemka     {"altitude", ValueIface::Unit::Meters},
344e0d371e4SVijay Khemka     {"current", ValueIface::Unit::Amperes},
345e0d371e4SVijay Khemka     {"power", ValueIface::Unit::Watts},
346e0d371e4SVijay Khemka     {"energy", ValueIface::Unit::Joules},
3472b56ddb3SKumar Thangavel     {"utilization", ValueIface::Unit::Percent},
3482b56ddb3SKumar Thangavel     {"airflow", ValueIface::Unit::CFM}};
349e0d371e4SVijay Khemka 
350abcc94faSVijay Khemka void VirtualSensors::createVirtualSensors()
351abcc94faSVijay Khemka {
352abcc94faSVijay Khemka     static const Json empty{};
353abcc94faSVijay Khemka 
354abcc94faSVijay Khemka     auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
355abcc94faSVijay Khemka     // print values
356abcc94faSVijay Khemka     if (DEBUG)
357abcc94faSVijay Khemka         std::cout << "Config json data:\n" << data << "\n\n";
358abcc94faSVijay Khemka 
359abcc94faSVijay Khemka     /* Get virtual sensors  config data */
360abcc94faSVijay Khemka     for (const auto& j : data)
361abcc94faSVijay Khemka     {
362abcc94faSVijay Khemka         auto desc = j.value("Desc", empty);
363abcc94faSVijay Khemka         if (!desc.empty())
364abcc94faSVijay Khemka         {
365abcc94faSVijay Khemka             std::string sensorType = desc.value("SensorType", "");
366abcc94faSVijay Khemka             std::string name = desc.value("Name", "");
367abcc94faSVijay Khemka 
368abcc94faSVijay Khemka             if (!name.empty() && !sensorType.empty())
369abcc94faSVijay Khemka             {
370e0d371e4SVijay Khemka                 if (unitMap.find(sensorType) == unitMap.end())
371e0d371e4SVijay Khemka                 {
372e0d371e4SVijay Khemka                     log<level::ERR>("Sensor type is not supported",
373e0d371e4SVijay Khemka                                     entry("TYPE = %s", sensorType.c_str()));
374e0d371e4SVijay Khemka                 }
375e0d371e4SVijay Khemka                 else
376e0d371e4SVijay Khemka                 {
377abcc94faSVijay Khemka                     std::string objPath(sensorDbusPath);
378abcc94faSVijay Khemka                     objPath += sensorType + "/" + name;
379abcc94faSVijay Khemka 
38032a7156bSVijay Khemka                     auto virtualSensorPtr = std::make_unique<VirtualSensor>(
38132a7156bSVijay Khemka                         bus, objPath.c_str(), j, name);
382abcc94faSVijay Khemka 
383abcc94faSVijay Khemka                     log<level::INFO>("Added a new virtual sensor",
384abcc94faSVijay Khemka                                      entry("NAME = %s", name.c_str()));
3853ed9a516SVijay Khemka                     virtualSensorPtr->updateVirtualSensor();
386e0d371e4SVijay Khemka 
387e0d371e4SVijay Khemka                     /* Initialize unit value for virtual sensor */
388e0d371e4SVijay Khemka                     virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
389e0d371e4SVijay Khemka 
3903ed9a516SVijay Khemka                     virtualSensorsMap.emplace(std::move(name),
3913ed9a516SVijay Khemka                                               std::move(virtualSensorPtr));
392abcc94faSVijay Khemka                 }
393e0d371e4SVijay Khemka             }
394abcc94faSVijay Khemka             else
395abcc94faSVijay Khemka             {
396abcc94faSVijay Khemka                 log<level::ERR>("Sensor type or name not found in config file");
397abcc94faSVijay Khemka             }
398abcc94faSVijay Khemka         }
399abcc94faSVijay Khemka         else
400abcc94faSVijay Khemka         {
401abcc94faSVijay Khemka             log<level::ERR>(
402abcc94faSVijay Khemka                 "Descriptor for new virtual sensor not found in config file");
403abcc94faSVijay Khemka         }
404abcc94faSVijay Khemka     }
405abcc94faSVijay Khemka }
406abcc94faSVijay Khemka 
407abcc94faSVijay Khemka } // namespace virtualSensor
408abcc94faSVijay Khemka } // namespace phosphor
409abcc94faSVijay Khemka 
410abcc94faSVijay Khemka /**
411abcc94faSVijay Khemka  * @brief Main
412abcc94faSVijay Khemka  */
413abcc94faSVijay Khemka int main()
414abcc94faSVijay Khemka {
415abcc94faSVijay Khemka 
416abcc94faSVijay Khemka     // Get a default event loop
417abcc94faSVijay Khemka     auto event = sdeventplus::Event::get_default();
418abcc94faSVijay Khemka 
419abcc94faSVijay Khemka     // Get a handle to system dbus
420abcc94faSVijay Khemka     auto bus = sdbusplus::bus::new_default();
421abcc94faSVijay Khemka 
4226c19e7d2SMatt Spinler     // Add the ObjectManager interface
4236c19e7d2SMatt Spinler     sdbusplus::server::manager::manager objManager(bus, "/");
4246c19e7d2SMatt Spinler 
425abcc94faSVijay Khemka     // Create an virtual sensors object
426abcc94faSVijay Khemka     phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
427abcc94faSVijay Khemka 
428abcc94faSVijay Khemka     // Request service bus name
429abcc94faSVijay Khemka     bus.request_name(busName);
430abcc94faSVijay Khemka 
431abcc94faSVijay Khemka     // Attach the bus to sd_event to service user requests
432abcc94faSVijay Khemka     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
433abcc94faSVijay Khemka     event.loop();
434abcc94faSVijay Khemka 
435abcc94faSVijay Khemka     return 0;
436abcc94faSVijay Khemka }
437