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 
750fcf0e1cSLei YU using AssociationList =
760fcf0e1cSLei YU     std::vector<std::tuple<std::string, std::string, std::string>>;
770fcf0e1cSLei YU 
780fcf0e1cSLei YU AssociationList getAssociationsFromJson(const Json& j)
790fcf0e1cSLei YU {
800fcf0e1cSLei YU     AssociationList assocs{};
810fcf0e1cSLei YU     try
820fcf0e1cSLei YU     {
830fcf0e1cSLei YU         j.get_to(assocs);
840fcf0e1cSLei YU     }
850fcf0e1cSLei YU     catch (const std::exception& ex)
860fcf0e1cSLei YU     {
870fcf0e1cSLei YU         log<level::ERR>("Failed to parse association",
880fcf0e1cSLei YU                         entry("EX=%s", ex.what()));
890fcf0e1cSLei YU     }
900fcf0e1cSLei YU     return assocs;
910fcf0e1cSLei YU }
920fcf0e1cSLei 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);
101f15189e3SMatt Spinler 
1023e99919bSRashmica Gupta     createThresholds(threshold, objPath);
103abcc94faSVijay Khemka 
104f6443742SHarvey Wu     /* Get MaxValue, MinValue setting if defined in config */
105f6443742SHarvey Wu     auto confDesc = sensorConfig.value("Desc", empty);
106f6443742SHarvey Wu     if (auto maxConf = confDesc.find("MaxValue");
107f6443742SHarvey Wu         maxConf != confDesc.end() && maxConf->is_number())
108f6443742SHarvey Wu     {
109f6443742SHarvey Wu         ValueIface::maxValue(maxConf->get<double>());
110f6443742SHarvey Wu     }
111f6443742SHarvey Wu     if (auto minConf = confDesc.find("MinValue");
112f6443742SHarvey Wu         minConf != confDesc.end() && minConf->is_number())
113f6443742SHarvey Wu     {
114f6443742SHarvey Wu         ValueIface::minValue(minConf->get<double>());
115f6443742SHarvey Wu     }
116f6443742SHarvey Wu 
1170fcf0e1cSLei YU     /* Get optional association */
1180fcf0e1cSLei YU     auto assocJson = sensorConfig.value("Associations", empty);
1190fcf0e1cSLei YU     if (!assocJson.empty())
1200fcf0e1cSLei YU     {
1210fcf0e1cSLei YU         auto assocs = getAssociationsFromJson(assocJson);
1220fcf0e1cSLei YU         if (!assocs.empty())
1230fcf0e1cSLei YU         {
1240fcf0e1cSLei YU             associationIface =
1250fcf0e1cSLei YU                 std::make_unique<AssociationObject>(bus, objPath.c_str());
1260fcf0e1cSLei YU             associationIface->associations(assocs);
1270fcf0e1cSLei YU         }
1280fcf0e1cSLei YU     }
1290fcf0e1cSLei YU 
130abcc94faSVijay Khemka     /* Get expression string */
131abcc94faSVijay Khemka     exprStr = sensorConfig.value("Expression", "");
132abcc94faSVijay Khemka 
133abcc94faSVijay Khemka     /* Get all the parameter listed in configuration */
134abcc94faSVijay Khemka     auto params = sensorConfig.value("Params", empty);
135abcc94faSVijay Khemka 
136abcc94faSVijay Khemka     /* Check for constant parameter */
137abcc94faSVijay Khemka     const auto& consParams = params.value("ConstParam", empty);
138abcc94faSVijay Khemka     if (!consParams.empty())
139abcc94faSVijay Khemka     {
140abcc94faSVijay Khemka         for (auto& j : consParams)
141abcc94faSVijay Khemka         {
142abcc94faSVijay Khemka             if (j.find("ParamName") != j.end())
143abcc94faSVijay Khemka             {
144abcc94faSVijay Khemka                 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
1453ed9a516SVijay Khemka                 std::string name = j["ParamName"];
1463ed9a516SVijay Khemka                 symbols.create_variable(name);
1473ed9a516SVijay Khemka                 paramMap.emplace(std::move(name), std::move(paramPtr));
148abcc94faSVijay Khemka             }
149abcc94faSVijay Khemka             else
150abcc94faSVijay Khemka             {
151abcc94faSVijay Khemka                 /* Invalid configuration */
152abcc94faSVijay Khemka                 throw std::invalid_argument(
153abcc94faSVijay Khemka                     "ParamName not found in configuration");
154abcc94faSVijay Khemka             }
155abcc94faSVijay Khemka         }
156abcc94faSVijay Khemka     }
157abcc94faSVijay Khemka 
1587452a867SVijay Khemka     /* Check for dbus parameter */
1597452a867SVijay Khemka     auto dbusParams = params.value("DbusParam", empty);
1607452a867SVijay Khemka     if (!dbusParams.empty())
1617452a867SVijay Khemka     {
1627452a867SVijay Khemka         for (auto& j : dbusParams)
1637452a867SVijay Khemka         {
1647452a867SVijay Khemka             /* Get parameter dbus sensor descriptor */
1657452a867SVijay Khemka             auto desc = j.value("Desc", empty);
1667452a867SVijay Khemka             if ((!desc.empty()) && (j.find("ParamName") != j.end()))
1677452a867SVijay Khemka             {
1687452a867SVijay Khemka                 std::string sensorType = desc.value("SensorType", "");
1697452a867SVijay Khemka                 std::string name = desc.value("Name", "");
1707452a867SVijay Khemka 
1717452a867SVijay Khemka                 if (!sensorType.empty() && !name.empty())
1727452a867SVijay Khemka                 {
1737452a867SVijay Khemka                     std::string objPath(sensorDbusPath);
1747452a867SVijay Khemka                     objPath += sensorType + "/" + name;
1757452a867SVijay Khemka 
17651f898e2SVijay Khemka                     auto paramPtr =
17751f898e2SVijay Khemka                         std::make_unique<SensorParam>(bus, objPath, this);
1783ed9a516SVijay Khemka                     std::string name = j["ParamName"];
1793ed9a516SVijay Khemka                     symbols.create_variable(name);
1803ed9a516SVijay Khemka                     paramMap.emplace(std::move(name), std::move(paramPtr));
1817452a867SVijay Khemka                 }
1827452a867SVijay Khemka             }
1837452a867SVijay Khemka         }
1847452a867SVijay Khemka     }
185abcc94faSVijay Khemka 
1863ed9a516SVijay Khemka     symbols.add_constants();
1879f1ef4f5SMatt Spinler     symbols.add_package(vecopsPackage);
1883ed9a516SVijay Khemka     expression.register_symbol_table(symbols);
1893ed9a516SVijay Khemka 
1903ed9a516SVijay Khemka     /* parser from exprtk */
1913ed9a516SVijay Khemka     exprtk::parser<double> parser{};
192ddc6dcd6SMatt Spinler     if (!parser.compile(exprStr, expression))
193ddc6dcd6SMatt Spinler     {
194ddc6dcd6SMatt Spinler         log<level::ERR>("Expression compilation failed");
195ddc6dcd6SMatt Spinler 
196ddc6dcd6SMatt Spinler         for (std::size_t i = 0; i < parser.error_count(); ++i)
197ddc6dcd6SMatt Spinler         {
198ddc6dcd6SMatt Spinler             auto error = parser.get_error(i);
199ddc6dcd6SMatt Spinler 
200ddc6dcd6SMatt Spinler             log<level::ERR>(
201ddc6dcd6SMatt Spinler                 fmt::format(
202ddc6dcd6SMatt Spinler                     "Position: {} Type: {} Message: {}", error.token.position,
203ddc6dcd6SMatt Spinler                     exprtk::parser_error::to_str(error.mode), error.diagnostic)
204ddc6dcd6SMatt Spinler                     .c_str());
205ddc6dcd6SMatt Spinler         }
206ddc6dcd6SMatt Spinler         throw std::runtime_error("Expression compilation failed");
207ddc6dcd6SMatt Spinler     }
2083ed9a516SVijay Khemka 
209abcc94faSVijay Khemka     /* Print all parameters for debug purpose only */
210abcc94faSVijay Khemka     if (DEBUG)
211abcc94faSVijay Khemka         printParams(paramMap);
212abcc94faSVijay Khemka }
213abcc94faSVijay Khemka 
214abcc94faSVijay Khemka void VirtualSensor::setSensorValue(double value)
215abcc94faSVijay Khemka {
216543bf668SPatrick Williams     value = std::clamp(value, ValueIface::minValue(), ValueIface::maxValue());
217abcc94faSVijay Khemka     ValueIface::value(value);
218abcc94faSVijay Khemka }
219abcc94faSVijay Khemka 
220abcc94faSVijay Khemka void VirtualSensor::updateVirtualSensor()
2213ed9a516SVijay Khemka {
2223ed9a516SVijay Khemka     for (auto& param : paramMap)
2233ed9a516SVijay Khemka     {
2243ed9a516SVijay Khemka         auto& name = param.first;
2253ed9a516SVijay Khemka         auto& data = param.second;
2263ed9a516SVijay Khemka         if (auto var = symbols.get_variable(name))
2273ed9a516SVijay Khemka         {
2283ed9a516SVijay Khemka             var->ref() = data->getParamValue();
2293ed9a516SVijay Khemka         }
2303ed9a516SVijay Khemka         else
2313ed9a516SVijay Khemka         {
2323ed9a516SVijay Khemka             /* Invalid parameter */
2333ed9a516SVijay Khemka             throw std::invalid_argument("ParamName not found in symbols");
2343ed9a516SVijay Khemka         }
2353ed9a516SVijay Khemka     }
2363ed9a516SVijay Khemka     double val = expression.value();
23732a7156bSVijay Khemka 
23832a7156bSVijay Khemka     /* Set sensor value to dbus interface */
2393ed9a516SVijay Khemka     setSensorValue(val);
24032a7156bSVijay Khemka 
2413ed9a516SVijay Khemka     if (DEBUG)
2423ed9a516SVijay Khemka         std::cout << "Sensor value is " << val << "\n";
24332a7156bSVijay Khemka 
2448f5e6119SMatt Spinler     /* Check sensor thresholds and log required message */
245b306b03dSMatt Spinler     checkThresholds(val, perfLossIface);
246fdb826d5SPatrick Williams     checkThresholds(val, warningIface);
247fdb826d5SPatrick Williams     checkThresholds(val, criticalIface);
248fdb826d5SPatrick Williams     checkThresholds(val, softShutdownIface);
249fdb826d5SPatrick Williams     checkThresholds(val, hardShutdownIface);
2503ed9a516SVijay Khemka }
251abcc94faSVijay Khemka 
2523e99919bSRashmica Gupta void VirtualSensor::createThresholds(const Json& threshold,
2533e99919bSRashmica Gupta                                      const std::string& objPath)
2543e99919bSRashmica Gupta {
2553e99919bSRashmica Gupta     if (threshold.empty())
2563e99919bSRashmica Gupta     {
2573e99919bSRashmica Gupta         return;
2583e99919bSRashmica Gupta     }
2593e99919bSRashmica Gupta     // Only create the threshold interfaces if
2603e99919bSRashmica Gupta     // at least one of their values is present.
2613e99919bSRashmica Gupta     if (threshold.contains("CriticalHigh") || threshold.contains("CriticalLow"))
2623e99919bSRashmica Gupta     {
2633e99919bSRashmica Gupta         criticalIface =
2643e99919bSRashmica Gupta             std::make_unique<Threshold<CriticalObject>>(bus, objPath.c_str());
2653e99919bSRashmica Gupta 
2663e99919bSRashmica Gupta         criticalIface->criticalHigh(threshold.value(
2673e99919bSRashmica Gupta             "CriticalHigh", std::numeric_limits<double>::quiet_NaN()));
2683e99919bSRashmica Gupta         criticalIface->criticalLow(threshold.value(
2693e99919bSRashmica Gupta             "CriticalLow", std::numeric_limits<double>::quiet_NaN()));
2703e99919bSRashmica Gupta     }
2713e99919bSRashmica Gupta 
2723e99919bSRashmica Gupta     if (threshold.contains("WarningHigh") || threshold.contains("WarningLow"))
2733e99919bSRashmica Gupta     {
2743e99919bSRashmica Gupta         warningIface =
2753e99919bSRashmica Gupta             std::make_unique<Threshold<WarningObject>>(bus, objPath.c_str());
2763e99919bSRashmica Gupta 
2773e99919bSRashmica Gupta         warningIface->warningHigh(threshold.value(
2783e99919bSRashmica Gupta             "WarningHigh", std::numeric_limits<double>::quiet_NaN()));
2793e99919bSRashmica Gupta         warningIface->warningLow(threshold.value(
2803e99919bSRashmica Gupta             "WarningLow", std::numeric_limits<double>::quiet_NaN()));
2813e99919bSRashmica Gupta     }
2823e99919bSRashmica Gupta 
2833e99919bSRashmica Gupta     if (threshold.contains("HardShutdownHigh") ||
2843e99919bSRashmica Gupta         threshold.contains("HardShutdownLow"))
2853e99919bSRashmica Gupta     {
2863e99919bSRashmica Gupta         hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>(
2873e99919bSRashmica Gupta             bus, objPath.c_str());
2883e99919bSRashmica Gupta 
2893e99919bSRashmica Gupta         hardShutdownIface->hardShutdownHigh(threshold.value(
2903e99919bSRashmica Gupta             "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
2913e99919bSRashmica Gupta         hardShutdownIface->hardShutdownLow(threshold.value(
2923e99919bSRashmica Gupta             "HardShutdownLow", std::numeric_limits<double>::quiet_NaN()));
2933e99919bSRashmica Gupta     }
2943e99919bSRashmica Gupta 
2953e99919bSRashmica Gupta     if (threshold.contains("SoftShutdownHigh") ||
2963e99919bSRashmica Gupta         threshold.contains("SoftShutdownLow"))
2973e99919bSRashmica Gupta     {
2983e99919bSRashmica Gupta         softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>(
2993e99919bSRashmica Gupta             bus, objPath.c_str());
3003e99919bSRashmica Gupta 
3013e99919bSRashmica Gupta         softShutdownIface->softShutdownHigh(threshold.value(
3023e99919bSRashmica Gupta             "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
3033e99919bSRashmica Gupta         softShutdownIface->softShutdownLow(threshold.value(
3043e99919bSRashmica Gupta             "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN()));
3053e99919bSRashmica Gupta     }
3063e99919bSRashmica Gupta 
3073e99919bSRashmica Gupta     if (threshold.contains("PerformanceLossHigh") ||
3083e99919bSRashmica Gupta         threshold.contains("PerformanceLossLow"))
3093e99919bSRashmica Gupta     {
3103e99919bSRashmica Gupta         perfLossIface = std::make_unique<Threshold<PerformanceLossObject>>(
3113e99919bSRashmica Gupta             bus, objPath.c_str());
3123e99919bSRashmica Gupta 
3133e99919bSRashmica Gupta         perfLossIface->performanceLossHigh(threshold.value(
3143e99919bSRashmica Gupta             "PerformanceLossHigh", std::numeric_limits<double>::quiet_NaN()));
3153e99919bSRashmica Gupta         perfLossIface->performanceLossLow(threshold.value(
3163e99919bSRashmica Gupta             "PerformanceLossLow", std::numeric_limits<double>::quiet_NaN()));
3173e99919bSRashmica Gupta     }
3183e99919bSRashmica Gupta }
3193e99919bSRashmica Gupta 
320abcc94faSVijay Khemka /** @brief Parsing Virtual Sensor config JSON file  */
321abcc94faSVijay Khemka Json VirtualSensors::parseConfigFile(const std::string configFile)
322abcc94faSVijay Khemka {
323abcc94faSVijay Khemka     std::ifstream jsonFile(configFile);
324abcc94faSVijay Khemka     if (!jsonFile.is_open())
325abcc94faSVijay Khemka     {
326abcc94faSVijay Khemka         log<level::ERR>("config JSON file not found",
327abcc94faSVijay Khemka                         entry("FILENAME=%s", configFile.c_str()));
328abcc94faSVijay Khemka         throw std::exception{};
329abcc94faSVijay Khemka     }
330abcc94faSVijay Khemka 
331abcc94faSVijay Khemka     auto data = Json::parse(jsonFile, nullptr, false);
332abcc94faSVijay Khemka     if (data.is_discarded())
333abcc94faSVijay Khemka     {
334abcc94faSVijay Khemka         log<level::ERR>("config readings JSON parser failure",
335abcc94faSVijay Khemka                         entry("FILENAME=%s", configFile.c_str()));
336abcc94faSVijay Khemka         throw std::exception{};
337abcc94faSVijay Khemka     }
338abcc94faSVijay Khemka 
339abcc94faSVijay Khemka     return data;
340abcc94faSVijay Khemka }
341abcc94faSVijay Khemka 
342e0d371e4SVijay Khemka std::map<std::string, ValueIface::Unit> unitMap = {
343e0d371e4SVijay Khemka     {"temperature", ValueIface::Unit::DegreesC},
344e0d371e4SVijay Khemka     {"fan_tach", ValueIface::Unit::RPMS},
345e0d371e4SVijay Khemka     {"voltage", ValueIface::Unit::Volts},
346e0d371e4SVijay Khemka     {"altitude", ValueIface::Unit::Meters},
347e0d371e4SVijay Khemka     {"current", ValueIface::Unit::Amperes},
348e0d371e4SVijay Khemka     {"power", ValueIface::Unit::Watts},
349e0d371e4SVijay Khemka     {"energy", ValueIface::Unit::Joules},
3502b56ddb3SKumar Thangavel     {"utilization", ValueIface::Unit::Percent},
3514ac7a7f2SRashmica Gupta     {"airflow", ValueIface::Unit::CFM},
3524ac7a7f2SRashmica Gupta     {"pressure", ValueIface::Unit::Pascals}};
353e0d371e4SVijay Khemka 
354abcc94faSVijay Khemka void VirtualSensors::createVirtualSensors()
355abcc94faSVijay Khemka {
356abcc94faSVijay Khemka     static const Json empty{};
357abcc94faSVijay Khemka 
358abcc94faSVijay Khemka     auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
359abcc94faSVijay Khemka     // print values
360abcc94faSVijay Khemka     if (DEBUG)
361abcc94faSVijay Khemka         std::cout << "Config json data:\n" << data << "\n\n";
362abcc94faSVijay Khemka 
363abcc94faSVijay Khemka     /* Get virtual sensors  config data */
364abcc94faSVijay Khemka     for (const auto& j : data)
365abcc94faSVijay Khemka     {
366abcc94faSVijay Khemka         auto desc = j.value("Desc", empty);
367abcc94faSVijay Khemka         if (!desc.empty())
368abcc94faSVijay Khemka         {
369abcc94faSVijay Khemka             std::string sensorType = desc.value("SensorType", "");
370abcc94faSVijay Khemka             std::string name = desc.value("Name", "");
371665a0a29SRashmica Gupta             std::replace(name.begin(), name.end(), ' ', '_');
372abcc94faSVijay Khemka 
373abcc94faSVijay Khemka             if (!name.empty() && !sensorType.empty())
374abcc94faSVijay Khemka             {
375e0d371e4SVijay Khemka                 if (unitMap.find(sensorType) == unitMap.end())
376e0d371e4SVijay Khemka                 {
377e0d371e4SVijay Khemka                     log<level::ERR>("Sensor type is not supported",
378e0d371e4SVijay Khemka                                     entry("TYPE=%s", sensorType.c_str()));
379e0d371e4SVijay Khemka                 }
380e0d371e4SVijay Khemka                 else
381e0d371e4SVijay Khemka                 {
38267d8b9d2SRashmica Gupta                     if (virtualSensorsMap.find(name) != virtualSensorsMap.end())
38367d8b9d2SRashmica Gupta                     {
38467d8b9d2SRashmica Gupta                         log<level::ERR>(
38567d8b9d2SRashmica Gupta                             "A virtual sensor with this name already exists",
38667d8b9d2SRashmica Gupta                             entry("TYPE=%s", name.c_str()));
38767d8b9d2SRashmica Gupta                         continue;
38867d8b9d2SRashmica Gupta                     }
389abcc94faSVijay Khemka                     std::string objPath(sensorDbusPath);
390abcc94faSVijay Khemka                     objPath += sensorType + "/" + name;
391abcc94faSVijay Khemka 
39232a7156bSVijay Khemka                     auto virtualSensorPtr = std::make_unique<VirtualSensor>(
39332a7156bSVijay Khemka                         bus, objPath.c_str(), j, name);
394abcc94faSVijay Khemka 
395abcc94faSVijay Khemka                     log<level::INFO>("Added a new virtual sensor",
396abcc94faSVijay Khemka                                      entry("NAME=%s", name.c_str()));
3973ed9a516SVijay Khemka                     virtualSensorPtr->updateVirtualSensor();
398e0d371e4SVijay Khemka 
399e0d371e4SVijay Khemka                     /* Initialize unit value for virtual sensor */
400e0d371e4SVijay Khemka                     virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
401*a2fa63a6SRashmica Gupta                     virtualSensorPtr->emit_object_added();
402e0d371e4SVijay Khemka 
4033ed9a516SVijay Khemka                     virtualSensorsMap.emplace(std::move(name),
4043ed9a516SVijay Khemka                                               std::move(virtualSensorPtr));
405abcc94faSVijay Khemka                 }
406e0d371e4SVijay Khemka             }
407abcc94faSVijay Khemka             else
408abcc94faSVijay Khemka             {
409abcc94faSVijay Khemka                 log<level::ERR>("Sensor type or name not found in config file");
410abcc94faSVijay Khemka             }
411abcc94faSVijay Khemka         }
412abcc94faSVijay Khemka         else
413abcc94faSVijay Khemka         {
414abcc94faSVijay Khemka             log<level::ERR>(
415abcc94faSVijay Khemka                 "Descriptor for new virtual sensor not found in config file");
416abcc94faSVijay Khemka         }
417abcc94faSVijay Khemka     }
418abcc94faSVijay Khemka }
419abcc94faSVijay Khemka 
420abcc94faSVijay Khemka } // namespace virtualSensor
421abcc94faSVijay Khemka } // namespace phosphor
422abcc94faSVijay Khemka 
423abcc94faSVijay Khemka /**
424abcc94faSVijay Khemka  * @brief Main
425abcc94faSVijay Khemka  */
426abcc94faSVijay Khemka int main()
427abcc94faSVijay Khemka {
428abcc94faSVijay Khemka 
429abcc94faSVijay Khemka     // Get a default event loop
430abcc94faSVijay Khemka     auto event = sdeventplus::Event::get_default();
431abcc94faSVijay Khemka 
432abcc94faSVijay Khemka     // Get a handle to system dbus
433abcc94faSVijay Khemka     auto bus = sdbusplus::bus::new_default();
434abcc94faSVijay Khemka 
4356c19e7d2SMatt Spinler     // Add the ObjectManager interface
4366c19e7d2SMatt Spinler     sdbusplus::server::manager::manager objManager(bus, "/");
4376c19e7d2SMatt Spinler 
438abcc94faSVijay Khemka     // Create an virtual sensors object
439abcc94faSVijay Khemka     phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
440abcc94faSVijay Khemka 
441abcc94faSVijay Khemka     // Request service bus name
442abcc94faSVijay Khemka     bus.request_name(busName);
443abcc94faSVijay Khemka 
444abcc94faSVijay Khemka     // Attach the bus to sd_event to service user requests
445abcc94faSVijay Khemka     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
446abcc94faSVijay Khemka     event.loop();
447abcc94faSVijay Khemka 
448abcc94faSVijay Khemka     return 0;
449abcc94faSVijay Khemka }
450