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 static constexpr uint8_t defaultHighThreshold = 100;
17abcc94faSVijay Khemka static constexpr uint8_t defaultLowThreshold = 0;
18abcc94faSVijay Khemka 
19abcc94faSVijay Khemka using namespace phosphor::logging;
20abcc94faSVijay Khemka 
2151f898e2SVijay Khemka int handleDbusSignal(sd_bus_message* msg, void* usrData, sd_bus_error*)
2251f898e2SVijay Khemka {
2351f898e2SVijay Khemka     if (usrData == nullptr)
2451f898e2SVijay Khemka     {
2551f898e2SVijay Khemka         throw std::runtime_error("Invalid match");
2651f898e2SVijay Khemka     }
2751f898e2SVijay Khemka 
2851f898e2SVijay Khemka     auto sdbpMsg = sdbusplus::message::message(msg);
2951f898e2SVijay Khemka     std::string msgIfce;
3051f898e2SVijay Khemka     std::map<std::string, std::variant<int64_t, double, bool>> msgData;
3151f898e2SVijay Khemka 
3251f898e2SVijay Khemka     sdbpMsg.read(msgIfce, msgData);
3351f898e2SVijay Khemka 
3451f898e2SVijay Khemka     if (msgData.find("Value") != msgData.end())
3551f898e2SVijay Khemka     {
3651f898e2SVijay Khemka         using namespace phosphor::virtualSensor;
3751f898e2SVijay Khemka         VirtualSensor* obj = static_cast<VirtualSensor*>(usrData);
3851f898e2SVijay Khemka         // TODO(openbmc/phosphor-virtual-sensor#1): updateVirtualSensor should
3951f898e2SVijay Khemka         // be changed to take the information we got from the signal, to avoid
4051f898e2SVijay Khemka         // having to do numerous dbus queries.
4151f898e2SVijay Khemka         obj->updateVirtualSensor();
4251f898e2SVijay Khemka     }
4351f898e2SVijay Khemka     return 0;
4451f898e2SVijay Khemka }
4551f898e2SVijay Khemka 
46abcc94faSVijay Khemka namespace phosphor
47abcc94faSVijay Khemka {
48abcc94faSVijay Khemka namespace virtualSensor
49abcc94faSVijay Khemka {
50abcc94faSVijay Khemka 
51abcc94faSVijay Khemka void printParams(const VirtualSensor::ParamMap& paramMap)
52abcc94faSVijay Khemka {
53abcc94faSVijay Khemka     for (const auto& p : paramMap)
54abcc94faSVijay Khemka     {
55abcc94faSVijay Khemka         const auto& p1 = p.first;
56abcc94faSVijay Khemka         const auto& p2 = p.second;
57abcc94faSVijay Khemka         auto val = p2->getParamValue();
58abcc94faSVijay Khemka         std::cout << p1 << " = " << val << "\n";
59abcc94faSVijay Khemka     }
60abcc94faSVijay Khemka }
61abcc94faSVijay Khemka 
62abcc94faSVijay Khemka double SensorParam::getParamValue()
63abcc94faSVijay Khemka {
64abcc94faSVijay Khemka     switch (paramType)
65abcc94faSVijay Khemka     {
66abcc94faSVijay Khemka         case constParam:
67abcc94faSVijay Khemka             return value;
68abcc94faSVijay Khemka             break;
697452a867SVijay Khemka         case dbusParam:
707452a867SVijay Khemka             return dbusSensor->getSensorValue();
717452a867SVijay Khemka             break;
72abcc94faSVijay Khemka         default:
73abcc94faSVijay Khemka             throw std::invalid_argument("param type not supported");
74abcc94faSVijay Khemka     }
75abcc94faSVijay Khemka }
76abcc94faSVijay Khemka 
77*ce675228SMatt Spinler void VirtualSensor::initVirtualSensor(const Json& sensorConfig,
78*ce675228SMatt Spinler                                       const std::string& objPath)
79abcc94faSVijay Khemka {
80abcc94faSVijay Khemka 
81abcc94faSVijay Khemka     static const Json empty{};
82abcc94faSVijay Khemka 
83abcc94faSVijay Khemka     /* Get threshold values if defined in config */
84abcc94faSVijay Khemka     auto threshold = sensorConfig.value("Threshold", empty);
85abcc94faSVijay Khemka     if (!threshold.empty())
86abcc94faSVijay Khemka     {
87*ce675228SMatt Spinler         criticalIface = std::make_unique<CriticalObject>(bus, objPath.c_str());
88*ce675228SMatt Spinler         criticalIface->criticalHigh(
89*ce675228SMatt Spinler             threshold.value("CriticalHigh", defaultHighThreshold));
90*ce675228SMatt Spinler         criticalIface->criticalLow(
91*ce675228SMatt Spinler             threshold.value("CriticalLow", defaultLowThreshold));
92abcc94faSVijay Khemka 
93*ce675228SMatt Spinler         warningIface = std::make_unique<WarningObject>(bus, objPath.c_str());
94*ce675228SMatt Spinler         warningIface->warningHigh(
95*ce675228SMatt Spinler             threshold.value("WarningHigh", defaultHighThreshold));
96*ce675228SMatt Spinler         warningIface->warningLow(
97*ce675228SMatt Spinler             threshold.value("WarningLow", defaultLowThreshold));
98*ce675228SMatt Spinler 
99*ce675228SMatt Spinler         // Only create the high and low shutdown interfaces if
100*ce675228SMatt Spinler         // at least one of their values is present.
101*ce675228SMatt Spinler         if (threshold.contains("HardShutdownHigh") ||
102*ce675228SMatt Spinler             threshold.contains("HardShutdownLow"))
103*ce675228SMatt Spinler         {
104*ce675228SMatt Spinler             hardShutdownIface =
105*ce675228SMatt Spinler                 std::make_unique<HardShutdownObject>(bus, objPath.c_str());
106*ce675228SMatt Spinler 
107*ce675228SMatt Spinler             hardShutdownIface->hardShutdownHigh(threshold.value(
108*ce675228SMatt Spinler                 "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
109*ce675228SMatt Spinler             hardShutdownIface->hardShutdownLow(threshold.value(
110*ce675228SMatt Spinler                 "HardShutdownLow", std::numeric_limits<double>::quiet_NaN()));
111*ce675228SMatt Spinler         }
112*ce675228SMatt Spinler 
113*ce675228SMatt Spinler         if (threshold.contains("SoftShutdownHigh") ||
114*ce675228SMatt Spinler             threshold.contains("SoftShutdownLow"))
115*ce675228SMatt Spinler         {
116*ce675228SMatt Spinler             softShutdownIface =
117*ce675228SMatt Spinler                 std::make_unique<SoftShutdownObject>(bus, objPath.c_str());
118*ce675228SMatt Spinler 
119*ce675228SMatt Spinler             softShutdownIface->softShutdownHigh(threshold.value(
120*ce675228SMatt Spinler                 "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
121*ce675228SMatt Spinler             softShutdownIface->softShutdownLow(threshold.value(
122*ce675228SMatt Spinler                 "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN()));
123*ce675228SMatt Spinler         }
124c62a5548SVijay Khemka     }
125abcc94faSVijay Khemka 
126abcc94faSVijay Khemka     /* Get expression string */
127abcc94faSVijay Khemka     exprStr = sensorConfig.value("Expression", "");
128abcc94faSVijay Khemka 
129abcc94faSVijay Khemka     /* Get all the parameter listed in configuration */
130abcc94faSVijay Khemka     auto params = sensorConfig.value("Params", empty);
131abcc94faSVijay Khemka 
132abcc94faSVijay Khemka     /* Check for constant parameter */
133abcc94faSVijay Khemka     const auto& consParams = params.value("ConstParam", empty);
134abcc94faSVijay Khemka     if (!consParams.empty())
135abcc94faSVijay Khemka     {
136abcc94faSVijay Khemka         for (auto& j : consParams)
137abcc94faSVijay Khemka         {
138abcc94faSVijay Khemka             if (j.find("ParamName") != j.end())
139abcc94faSVijay Khemka             {
140abcc94faSVijay Khemka                 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
1413ed9a516SVijay Khemka                 std::string name = j["ParamName"];
1423ed9a516SVijay Khemka                 symbols.create_variable(name);
1433ed9a516SVijay Khemka                 paramMap.emplace(std::move(name), std::move(paramPtr));
144abcc94faSVijay Khemka             }
145abcc94faSVijay Khemka             else
146abcc94faSVijay Khemka             {
147abcc94faSVijay Khemka                 /* Invalid configuration */
148abcc94faSVijay Khemka                 throw std::invalid_argument(
149abcc94faSVijay Khemka                     "ParamName not found in configuration");
150abcc94faSVijay Khemka             }
151abcc94faSVijay Khemka         }
152abcc94faSVijay Khemka     }
153abcc94faSVijay Khemka 
1547452a867SVijay Khemka     /* Check for dbus parameter */
1557452a867SVijay Khemka     auto dbusParams = params.value("DbusParam", empty);
1567452a867SVijay Khemka     if (!dbusParams.empty())
1577452a867SVijay Khemka     {
1587452a867SVijay Khemka         for (auto& j : dbusParams)
1597452a867SVijay Khemka         {
1607452a867SVijay Khemka             /* Get parameter dbus sensor descriptor */
1617452a867SVijay Khemka             auto desc = j.value("Desc", empty);
1627452a867SVijay Khemka             if ((!desc.empty()) && (j.find("ParamName") != j.end()))
1637452a867SVijay Khemka             {
1647452a867SVijay Khemka                 std::string sensorType = desc.value("SensorType", "");
1657452a867SVijay Khemka                 std::string name = desc.value("Name", "");
1667452a867SVijay Khemka 
1677452a867SVijay Khemka                 if (!sensorType.empty() && !name.empty())
1687452a867SVijay Khemka                 {
1697452a867SVijay Khemka                     std::string objPath(sensorDbusPath);
1707452a867SVijay Khemka                     objPath += sensorType + "/" + name;
1717452a867SVijay Khemka 
17251f898e2SVijay Khemka                     auto paramPtr =
17351f898e2SVijay Khemka                         std::make_unique<SensorParam>(bus, objPath, this);
1743ed9a516SVijay Khemka                     std::string name = j["ParamName"];
1753ed9a516SVijay Khemka                     symbols.create_variable(name);
1763ed9a516SVijay Khemka                     paramMap.emplace(std::move(name), std::move(paramPtr));
1777452a867SVijay Khemka                 }
1787452a867SVijay Khemka             }
1797452a867SVijay Khemka         }
1807452a867SVijay Khemka     }
181abcc94faSVijay Khemka 
1823ed9a516SVijay Khemka     symbols.add_constants();
1839f1ef4f5SMatt Spinler     symbols.add_package(vecopsPackage);
1843ed9a516SVijay Khemka     expression.register_symbol_table(symbols);
1853ed9a516SVijay Khemka 
1863ed9a516SVijay Khemka     /* parser from exprtk */
1873ed9a516SVijay Khemka     exprtk::parser<double> parser{};
188ddc6dcd6SMatt Spinler     if (!parser.compile(exprStr, expression))
189ddc6dcd6SMatt Spinler     {
190ddc6dcd6SMatt Spinler         log<level::ERR>("Expression compilation failed");
191ddc6dcd6SMatt Spinler 
192ddc6dcd6SMatt Spinler         for (std::size_t i = 0; i < parser.error_count(); ++i)
193ddc6dcd6SMatt Spinler         {
194ddc6dcd6SMatt Spinler             auto error = parser.get_error(i);
195ddc6dcd6SMatt Spinler 
196ddc6dcd6SMatt Spinler             log<level::ERR>(
197ddc6dcd6SMatt Spinler                 fmt::format(
198ddc6dcd6SMatt Spinler                     "Position: {} Type: {} Message: {}", error.token.position,
199ddc6dcd6SMatt Spinler                     exprtk::parser_error::to_str(error.mode), error.diagnostic)
200ddc6dcd6SMatt Spinler                     .c_str());
201ddc6dcd6SMatt Spinler         }
202ddc6dcd6SMatt Spinler         throw std::runtime_error("Expression compilation failed");
203ddc6dcd6SMatt Spinler     }
2043ed9a516SVijay Khemka 
205abcc94faSVijay Khemka     /* Print all parameters for debug purpose only */
206abcc94faSVijay Khemka     if (DEBUG)
207abcc94faSVijay Khemka         printParams(paramMap);
208abcc94faSVijay Khemka }
209abcc94faSVijay Khemka 
210abcc94faSVijay Khemka void VirtualSensor::setSensorValue(double value)
211abcc94faSVijay Khemka {
212abcc94faSVijay Khemka     ValueIface::value(value);
213abcc94faSVijay Khemka }
214abcc94faSVijay Khemka 
21532a7156bSVijay Khemka void VirtualSensor::checkSensorThreshold(const double value)
21632a7156bSVijay Khemka {
217*ce675228SMatt Spinler     if (warningIface)
21832a7156bSVijay Khemka     {
219*ce675228SMatt Spinler         if (value >= warningIface->warningHigh())
22032a7156bSVijay Khemka         {
221*ce675228SMatt Spinler             if (!warningIface->warningAlarmHigh())
222*ce675228SMatt Spinler             {
223*ce675228SMatt Spinler                 warningIface->warningAlarmHigh(true);
22432a7156bSVijay Khemka                 log<level::ERR>("ASSERT: Virtual Sensor has exceeded "
22532a7156bSVijay Khemka                                 "warning high threshold",
22632a7156bSVijay Khemka                                 entry("NAME = %s", name.c_str()));
22732a7156bSVijay Khemka             }
22832a7156bSVijay Khemka         }
229*ce675228SMatt Spinler         else if (warningIface->warningAlarmHigh())
23032a7156bSVijay Khemka         {
231*ce675228SMatt Spinler             warningIface->warningAlarmHigh(false);
23232a7156bSVijay Khemka             log<level::INFO>("DEASSERT: Virtual Sensor is under "
23332a7156bSVijay Khemka                              "warning high threshold",
23432a7156bSVijay Khemka                              entry("NAME = %s", name.c_str()));
23532a7156bSVijay Khemka         }
23632a7156bSVijay Khemka 
237*ce675228SMatt Spinler         if (value <= warningIface->warningLow())
23832a7156bSVijay Khemka         {
239*ce675228SMatt Spinler             if (!warningIface->warningAlarmLow())
24032a7156bSVijay Khemka             {
241*ce675228SMatt Spinler                 warningIface->warningAlarmLow(true);
242*ce675228SMatt Spinler                 log<level::ERR>("ASSERT: Virtual Sensor is under "
243*ce675228SMatt Spinler                                 "warning low threshold",
244*ce675228SMatt Spinler                                 entry("NAME = %s", name.c_str()));
245*ce675228SMatt Spinler             }
246*ce675228SMatt Spinler         }
247*ce675228SMatt Spinler         else if (warningIface->warningAlarmLow())
248*ce675228SMatt Spinler         {
249*ce675228SMatt Spinler             warningIface->warningAlarmLow(false);
250*ce675228SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is above "
251*ce675228SMatt Spinler                              "warning low threshold",
252*ce675228SMatt Spinler                              entry("NAME = %s", name.c_str()));
253*ce675228SMatt Spinler         }
254*ce675228SMatt Spinler     }
255*ce675228SMatt Spinler 
256*ce675228SMatt Spinler     if (criticalIface)
257*ce675228SMatt Spinler     {
258*ce675228SMatt Spinler         if (value >= criticalIface->criticalHigh())
259*ce675228SMatt Spinler         {
260*ce675228SMatt Spinler             if (!criticalIface->criticalAlarmHigh())
261*ce675228SMatt Spinler             {
262*ce675228SMatt Spinler                 criticalIface->criticalAlarmHigh(true);
26326edaad4SMatt Spinler                 log<level::ERR>("ASSERT: Virtual Sensor has exceeded "
26426edaad4SMatt Spinler                                 "critical high threshold",
26532a7156bSVijay Khemka                                 entry("NAME = %s", name.c_str()));
26632a7156bSVijay Khemka             }
26732a7156bSVijay Khemka         }
268*ce675228SMatt Spinler         else if (criticalIface->criticalAlarmHigh())
26932a7156bSVijay Khemka         {
270*ce675228SMatt Spinler             criticalIface->criticalAlarmHigh(false);
27126edaad4SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is under "
27226edaad4SMatt Spinler                              "critical high threshold",
27332a7156bSVijay Khemka                              entry("NAME = %s", name.c_str()));
27432a7156bSVijay Khemka         }
27532a7156bSVijay Khemka 
276*ce675228SMatt Spinler         if (value <= criticalIface->criticalLow())
27732a7156bSVijay Khemka         {
278*ce675228SMatt Spinler             if (!criticalIface->criticalAlarmLow())
27932a7156bSVijay Khemka             {
280*ce675228SMatt Spinler                 criticalIface->criticalAlarmLow(true);
28132a7156bSVijay Khemka                 log<level::ERR>("ASSERT: Virtual Sensor is under "
282*ce675228SMatt Spinler                                 "critical low threshold",
28332a7156bSVijay Khemka                                 entry("NAME = %s", name.c_str()));
28432a7156bSVijay Khemka             }
28532a7156bSVijay Khemka         }
286*ce675228SMatt Spinler         else if (criticalIface->criticalAlarmLow())
28732a7156bSVijay Khemka         {
288*ce675228SMatt Spinler             criticalIface->criticalAlarmLow(false);
28926edaad4SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is above "
290*ce675228SMatt Spinler                              "critical low threshold",
291*ce675228SMatt Spinler                              entry("NAME = %s", name.c_str()));
292*ce675228SMatt Spinler         }
293*ce675228SMatt Spinler     }
294*ce675228SMatt Spinler 
295*ce675228SMatt Spinler     if (softShutdownIface)
296*ce675228SMatt Spinler     {
297*ce675228SMatt Spinler         if (value >= softShutdownIface->softShutdownHigh())
298*ce675228SMatt Spinler         {
299*ce675228SMatt Spinler             if (!softShutdownIface->softShutdownAlarmHigh())
300*ce675228SMatt Spinler             {
301*ce675228SMatt Spinler                 softShutdownIface->softShutdownAlarmHigh(true);
302*ce675228SMatt Spinler                 log<level::ERR>("ASSERT: Virtual Sensor has exceeded "
303*ce675228SMatt Spinler                                 "softShutdown high threshold",
304*ce675228SMatt Spinler                                 entry("NAME = %s", name.c_str()));
305*ce675228SMatt Spinler             }
306*ce675228SMatt Spinler         }
307*ce675228SMatt Spinler         else if (softShutdownIface->softShutdownAlarmHigh())
308*ce675228SMatt Spinler         {
309*ce675228SMatt Spinler             softShutdownIface->softShutdownAlarmHigh(false);
310*ce675228SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is under "
311*ce675228SMatt Spinler                              "softShutdown high threshold",
31232a7156bSVijay Khemka                              entry("NAME = %s", name.c_str()));
31332a7156bSVijay Khemka         }
31426edaad4SMatt Spinler 
315*ce675228SMatt Spinler         if (value <= softShutdownIface->softShutdownLow())
31626edaad4SMatt Spinler         {
317*ce675228SMatt Spinler             if (!softShutdownIface->softShutdownAlarmLow())
31826edaad4SMatt Spinler             {
319*ce675228SMatt Spinler                 softShutdownIface->softShutdownAlarmLow(true);
32026edaad4SMatt Spinler                 log<level::ERR>("ASSERT: Virtual Sensor is under "
321*ce675228SMatt Spinler                                 "softShutdown low threshold",
32226edaad4SMatt Spinler                                 entry("NAME = %s", name.c_str()));
32326edaad4SMatt Spinler             }
32426edaad4SMatt Spinler         }
325*ce675228SMatt Spinler         else if (softShutdownIface->softShutdownAlarmLow())
32626edaad4SMatt Spinler         {
327*ce675228SMatt Spinler             softShutdownIface->softShutdownAlarmLow(false);
32826edaad4SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is above "
329*ce675228SMatt Spinler                              "softShutdown low threshold",
33026edaad4SMatt Spinler                              entry("NAME = %s", name.c_str()));
33126edaad4SMatt Spinler         }
33232a7156bSVijay Khemka     }
33332a7156bSVijay Khemka 
334*ce675228SMatt Spinler     if (hardShutdownIface)
335*ce675228SMatt Spinler     {
336*ce675228SMatt Spinler         if (value >= hardShutdownIface->hardShutdownHigh())
337*ce675228SMatt Spinler         {
338*ce675228SMatt Spinler             if (!hardShutdownIface->hardShutdownAlarmHigh())
339*ce675228SMatt Spinler             {
340*ce675228SMatt Spinler                 hardShutdownIface->hardShutdownAlarmHigh(true);
341*ce675228SMatt Spinler                 log<level::ERR>("ASSERT: Virtual Sensor has exceeded "
342*ce675228SMatt Spinler                                 "hardShutdown high threshold",
343*ce675228SMatt Spinler                                 entry("NAME = %s", name.c_str()));
344*ce675228SMatt Spinler             }
345*ce675228SMatt Spinler         }
346*ce675228SMatt Spinler         else if (hardShutdownIface->hardShutdownAlarmHigh())
347*ce675228SMatt Spinler         {
348*ce675228SMatt Spinler             hardShutdownIface->hardShutdownAlarmHigh(false);
349*ce675228SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is under "
350*ce675228SMatt Spinler                              "hardShutdown high threshold",
351*ce675228SMatt Spinler                              entry("NAME = %s", name.c_str()));
352*ce675228SMatt Spinler         }
353*ce675228SMatt Spinler 
354*ce675228SMatt Spinler         if (value <= hardShutdownIface->hardShutdownLow())
355*ce675228SMatt Spinler         {
356*ce675228SMatt Spinler             if (!hardShutdownIface->hardShutdownAlarmLow())
357*ce675228SMatt Spinler             {
358*ce675228SMatt Spinler                 hardShutdownIface->hardShutdownAlarmLow(true);
359*ce675228SMatt Spinler                 log<level::ERR>("ASSERT: Virtual Sensor is under "
360*ce675228SMatt Spinler                                 "hardShutdown low threshold",
361*ce675228SMatt Spinler                                 entry("NAME = %s", name.c_str()));
362*ce675228SMatt Spinler             }
363*ce675228SMatt Spinler         }
364*ce675228SMatt Spinler         else if (hardShutdownIface->hardShutdownAlarmLow())
365*ce675228SMatt Spinler         {
366*ce675228SMatt Spinler             hardShutdownIface->hardShutdownAlarmLow(false);
367*ce675228SMatt Spinler             log<level::INFO>("DEASSERT: Virtual Sensor is above "
368*ce675228SMatt Spinler                              "hardShutdown low threshold",
369*ce675228SMatt Spinler                              entry("NAME = %s", name.c_str()));
370*ce675228SMatt Spinler         }
371*ce675228SMatt Spinler     }
372*ce675228SMatt Spinler }
373*ce675228SMatt Spinler 
374abcc94faSVijay Khemka void VirtualSensor::updateVirtualSensor()
3753ed9a516SVijay Khemka {
3763ed9a516SVijay Khemka     for (auto& param : paramMap)
3773ed9a516SVijay Khemka     {
3783ed9a516SVijay Khemka         auto& name = param.first;
3793ed9a516SVijay Khemka         auto& data = param.second;
3803ed9a516SVijay Khemka         if (auto var = symbols.get_variable(name))
3813ed9a516SVijay Khemka         {
3823ed9a516SVijay Khemka             var->ref() = data->getParamValue();
3833ed9a516SVijay Khemka         }
3843ed9a516SVijay Khemka         else
3853ed9a516SVijay Khemka         {
3863ed9a516SVijay Khemka             /* Invalid parameter */
3873ed9a516SVijay Khemka             throw std::invalid_argument("ParamName not found in symbols");
3883ed9a516SVijay Khemka         }
3893ed9a516SVijay Khemka     }
3903ed9a516SVijay Khemka     double val = expression.value();
39132a7156bSVijay Khemka 
39232a7156bSVijay Khemka     /* Set sensor value to dbus interface */
3933ed9a516SVijay Khemka     setSensorValue(val);
39432a7156bSVijay Khemka 
3953ed9a516SVijay Khemka     if (DEBUG)
3963ed9a516SVijay Khemka         std::cout << "Sensor value is " << val << "\n";
39732a7156bSVijay Khemka 
39832a7156bSVijay Khemka     /* Check sensor threshold and log required message */
39932a7156bSVijay Khemka     checkSensorThreshold(val);
4003ed9a516SVijay Khemka }
401abcc94faSVijay Khemka 
402abcc94faSVijay Khemka /** @brief Parsing Virtual Sensor config JSON file  */
403abcc94faSVijay Khemka Json VirtualSensors::parseConfigFile(const std::string configFile)
404abcc94faSVijay Khemka {
405abcc94faSVijay Khemka     std::ifstream jsonFile(configFile);
406abcc94faSVijay Khemka     if (!jsonFile.is_open())
407abcc94faSVijay Khemka     {
408abcc94faSVijay Khemka         log<level::ERR>("config JSON file not found",
409abcc94faSVijay Khemka                         entry("FILENAME = %s", configFile.c_str()));
410abcc94faSVijay Khemka         throw std::exception{};
411abcc94faSVijay Khemka     }
412abcc94faSVijay Khemka 
413abcc94faSVijay Khemka     auto data = Json::parse(jsonFile, nullptr, false);
414abcc94faSVijay Khemka     if (data.is_discarded())
415abcc94faSVijay Khemka     {
416abcc94faSVijay Khemka         log<level::ERR>("config readings JSON parser failure",
417abcc94faSVijay Khemka                         entry("FILENAME = %s", configFile.c_str()));
418abcc94faSVijay Khemka         throw std::exception{};
419abcc94faSVijay Khemka     }
420abcc94faSVijay Khemka 
421abcc94faSVijay Khemka     return data;
422abcc94faSVijay Khemka }
423abcc94faSVijay Khemka 
424e0d371e4SVijay Khemka std::map<std::string, ValueIface::Unit> unitMap = {
425e0d371e4SVijay Khemka     {"temperature", ValueIface::Unit::DegreesC},
426e0d371e4SVijay Khemka     {"fan_tach", ValueIface::Unit::RPMS},
427e0d371e4SVijay Khemka     {"voltage", ValueIface::Unit::Volts},
428e0d371e4SVijay Khemka     {"altitude", ValueIface::Unit::Meters},
429e0d371e4SVijay Khemka     {"current", ValueIface::Unit::Amperes},
430e0d371e4SVijay Khemka     {"power", ValueIface::Unit::Watts},
431e0d371e4SVijay Khemka     {"energy", ValueIface::Unit::Joules},
432e0d371e4SVijay Khemka     {"utilization", ValueIface::Unit::Percent}};
433e0d371e4SVijay Khemka 
434abcc94faSVijay Khemka void VirtualSensors::createVirtualSensors()
435abcc94faSVijay Khemka {
436abcc94faSVijay Khemka     static const Json empty{};
437abcc94faSVijay Khemka 
438abcc94faSVijay Khemka     auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
439abcc94faSVijay Khemka     // print values
440abcc94faSVijay Khemka     if (DEBUG)
441abcc94faSVijay Khemka         std::cout << "Config json data:\n" << data << "\n\n";
442abcc94faSVijay Khemka 
443abcc94faSVijay Khemka     /* Get virtual sensors  config data */
444abcc94faSVijay Khemka     for (const auto& j : data)
445abcc94faSVijay Khemka     {
446abcc94faSVijay Khemka         auto desc = j.value("Desc", empty);
447abcc94faSVijay Khemka         if (!desc.empty())
448abcc94faSVijay Khemka         {
449abcc94faSVijay Khemka             std::string sensorType = desc.value("SensorType", "");
450abcc94faSVijay Khemka             std::string name = desc.value("Name", "");
451abcc94faSVijay Khemka 
452abcc94faSVijay Khemka             if (!name.empty() && !sensorType.empty())
453abcc94faSVijay Khemka             {
454e0d371e4SVijay Khemka                 if (unitMap.find(sensorType) == unitMap.end())
455e0d371e4SVijay Khemka                 {
456e0d371e4SVijay Khemka                     log<level::ERR>("Sensor type is not supported",
457e0d371e4SVijay Khemka                                     entry("TYPE = %s", sensorType.c_str()));
458e0d371e4SVijay Khemka                 }
459e0d371e4SVijay Khemka                 else
460e0d371e4SVijay Khemka                 {
461abcc94faSVijay Khemka                     std::string objPath(sensorDbusPath);
462abcc94faSVijay Khemka                     objPath += sensorType + "/" + name;
463abcc94faSVijay Khemka 
46432a7156bSVijay Khemka                     auto virtualSensorPtr = std::make_unique<VirtualSensor>(
46532a7156bSVijay Khemka                         bus, objPath.c_str(), j, name);
466abcc94faSVijay Khemka 
467abcc94faSVijay Khemka                     log<level::INFO>("Added a new virtual sensor",
468abcc94faSVijay Khemka                                      entry("NAME = %s", name.c_str()));
4693ed9a516SVijay Khemka                     virtualSensorPtr->updateVirtualSensor();
470e0d371e4SVijay Khemka 
471e0d371e4SVijay Khemka                     /* Initialize unit value for virtual sensor */
472e0d371e4SVijay Khemka                     virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
473e0d371e4SVijay Khemka 
4743ed9a516SVijay Khemka                     virtualSensorsMap.emplace(std::move(name),
4753ed9a516SVijay Khemka                                               std::move(virtualSensorPtr));
476abcc94faSVijay Khemka                 }
477e0d371e4SVijay Khemka             }
478abcc94faSVijay Khemka             else
479abcc94faSVijay Khemka             {
480abcc94faSVijay Khemka                 log<level::ERR>("Sensor type or name not found in config file");
481abcc94faSVijay Khemka             }
482abcc94faSVijay Khemka         }
483abcc94faSVijay Khemka         else
484abcc94faSVijay Khemka         {
485abcc94faSVijay Khemka             log<level::ERR>(
486abcc94faSVijay Khemka                 "Descriptor for new virtual sensor not found in config file");
487abcc94faSVijay Khemka         }
488abcc94faSVijay Khemka     }
489abcc94faSVijay Khemka }
490abcc94faSVijay Khemka 
491abcc94faSVijay Khemka } // namespace virtualSensor
492abcc94faSVijay Khemka } // namespace phosphor
493abcc94faSVijay Khemka 
494abcc94faSVijay Khemka /**
495abcc94faSVijay Khemka  * @brief Main
496abcc94faSVijay Khemka  */
497abcc94faSVijay Khemka int main()
498abcc94faSVijay Khemka {
499abcc94faSVijay Khemka 
500abcc94faSVijay Khemka     // Get a default event loop
501abcc94faSVijay Khemka     auto event = sdeventplus::Event::get_default();
502abcc94faSVijay Khemka 
503abcc94faSVijay Khemka     // Get a handle to system dbus
504abcc94faSVijay Khemka     auto bus = sdbusplus::bus::new_default();
505abcc94faSVijay Khemka 
5066c19e7d2SMatt Spinler     // Add the ObjectManager interface
5076c19e7d2SMatt Spinler     sdbusplus::server::manager::manager objManager(bus, "/");
5086c19e7d2SMatt Spinler 
509abcc94faSVijay Khemka     // Create an virtual sensors object
510abcc94faSVijay Khemka     phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
511abcc94faSVijay Khemka 
512abcc94faSVijay Khemka     // Request service bus name
513abcc94faSVijay Khemka     bus.request_name(busName);
514abcc94faSVijay Khemka 
515abcc94faSVijay Khemka     // Attach the bus to sd_event to service user requests
516abcc94faSVijay Khemka     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
517abcc94faSVijay Khemka     event.loop();
518abcc94faSVijay Khemka 
519abcc94faSVijay Khemka     return 0;
520abcc94faSVijay Khemka }
521