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/";
16*e7efe135SRashmica Gupta static constexpr auto entityManagerBusName =
17*e7efe135SRashmica Gupta     "xyz.openbmc_project.EntityManager";
18*e7efe135SRashmica Gupta static constexpr auto vsThresholdsIfaceSuffix = ".Thresholds";
19*e7efe135SRashmica Gupta static constexpr std::array<const char*, 0> calculationIfaces = {};
20abcc94faSVijay Khemka 
21abcc94faSVijay Khemka using namespace phosphor::logging;
22abcc94faSVijay Khemka 
2351f898e2SVijay Khemka int handleDbusSignal(sd_bus_message* msg, void* usrData, sd_bus_error*)
2451f898e2SVijay Khemka {
2551f898e2SVijay Khemka     if (usrData == nullptr)
2651f898e2SVijay Khemka     {
2751f898e2SVijay Khemka         throw std::runtime_error("Invalid match");
2851f898e2SVijay Khemka     }
2951f898e2SVijay Khemka 
3051f898e2SVijay Khemka     auto sdbpMsg = sdbusplus::message::message(msg);
3151f898e2SVijay Khemka     std::string msgIfce;
3251f898e2SVijay Khemka     std::map<std::string, std::variant<int64_t, double, bool>> msgData;
3351f898e2SVijay Khemka 
3451f898e2SVijay Khemka     sdbpMsg.read(msgIfce, msgData);
3551f898e2SVijay Khemka 
3651f898e2SVijay Khemka     if (msgData.find("Value") != msgData.end())
3751f898e2SVijay Khemka     {
3851f898e2SVijay Khemka         using namespace phosphor::virtualSensor;
3951f898e2SVijay Khemka         VirtualSensor* obj = static_cast<VirtualSensor*>(usrData);
4051f898e2SVijay Khemka         // TODO(openbmc/phosphor-virtual-sensor#1): updateVirtualSensor should
4151f898e2SVijay Khemka         // be changed to take the information we got from the signal, to avoid
4251f898e2SVijay Khemka         // having to do numerous dbus queries.
4351f898e2SVijay Khemka         obj->updateVirtualSensor();
4451f898e2SVijay Khemka     }
4551f898e2SVijay Khemka     return 0;
4651f898e2SVijay Khemka }
4751f898e2SVijay Khemka 
48abcc94faSVijay Khemka namespace phosphor
49abcc94faSVijay Khemka {
50abcc94faSVijay Khemka namespace virtualSensor
51abcc94faSVijay Khemka {
52abcc94faSVijay Khemka 
53abcc94faSVijay Khemka void printParams(const VirtualSensor::ParamMap& paramMap)
54abcc94faSVijay Khemka {
55abcc94faSVijay Khemka     for (const auto& p : paramMap)
56abcc94faSVijay Khemka     {
57abcc94faSVijay Khemka         const auto& p1 = p.first;
58abcc94faSVijay Khemka         const auto& p2 = p.second;
59abcc94faSVijay Khemka         auto val = p2->getParamValue();
60abcc94faSVijay Khemka         std::cout << p1 << " = " << val << "\n";
61abcc94faSVijay Khemka     }
62abcc94faSVijay Khemka }
63abcc94faSVijay Khemka 
64abcc94faSVijay Khemka double SensorParam::getParamValue()
65abcc94faSVijay Khemka {
66abcc94faSVijay Khemka     switch (paramType)
67abcc94faSVijay Khemka     {
68abcc94faSVijay Khemka         case constParam:
69abcc94faSVijay Khemka             return value;
70abcc94faSVijay Khemka             break;
717452a867SVijay Khemka         case dbusParam:
727452a867SVijay Khemka             return dbusSensor->getSensorValue();
737452a867SVijay Khemka             break;
74abcc94faSVijay Khemka         default:
75abcc94faSVijay Khemka             throw std::invalid_argument("param type not supported");
76abcc94faSVijay Khemka     }
77abcc94faSVijay Khemka }
78abcc94faSVijay Khemka 
790fcf0e1cSLei YU using AssociationList =
800fcf0e1cSLei YU     std::vector<std::tuple<std::string, std::string, std::string>>;
810fcf0e1cSLei YU 
820fcf0e1cSLei YU AssociationList getAssociationsFromJson(const Json& j)
830fcf0e1cSLei YU {
840fcf0e1cSLei YU     AssociationList assocs{};
850fcf0e1cSLei YU     try
860fcf0e1cSLei YU     {
870fcf0e1cSLei YU         j.get_to(assocs);
880fcf0e1cSLei YU     }
890fcf0e1cSLei YU     catch (const std::exception& ex)
900fcf0e1cSLei YU     {
910fcf0e1cSLei YU         log<level::ERR>("Failed to parse association",
920fcf0e1cSLei YU                         entry("EX=%s", ex.what()));
930fcf0e1cSLei YU     }
940fcf0e1cSLei YU     return assocs;
950fcf0e1cSLei YU }
960fcf0e1cSLei YU 
97*e7efe135SRashmica Gupta template <typename U>
98*e7efe135SRashmica Gupta struct VariantToNumber
99*e7efe135SRashmica Gupta {
100*e7efe135SRashmica Gupta     template <typename T>
101*e7efe135SRashmica Gupta     U operator()(const T& t) const
102*e7efe135SRashmica Gupta     {
103*e7efe135SRashmica Gupta         if constexpr (std::is_convertible<T, U>::value)
104*e7efe135SRashmica Gupta         {
105*e7efe135SRashmica Gupta             return static_cast<U>(t);
106*e7efe135SRashmica Gupta         }
107*e7efe135SRashmica Gupta         throw std::invalid_argument("Invalid number type in config\n");
108*e7efe135SRashmica Gupta     }
109*e7efe135SRashmica Gupta };
110*e7efe135SRashmica Gupta 
111*e7efe135SRashmica Gupta template <typename U>
112*e7efe135SRashmica Gupta U getNumberFromConfig(const PropertyMap& map, const std::string& name,
113*e7efe135SRashmica Gupta                       bool required)
114*e7efe135SRashmica Gupta {
115*e7efe135SRashmica Gupta     if (auto itr = map.find(name); itr != map.end())
116*e7efe135SRashmica Gupta     {
117*e7efe135SRashmica Gupta         return std::visit(VariantToNumber<U>(), itr->second);
118*e7efe135SRashmica Gupta     }
119*e7efe135SRashmica Gupta     else if (required)
120*e7efe135SRashmica Gupta     {
121*e7efe135SRashmica Gupta         log<level::ERR>("Required field missing in config",
122*e7efe135SRashmica Gupta                         entry("NAME=%s", name.c_str()));
123*e7efe135SRashmica Gupta         throw std::invalid_argument("Required field missing in config");
124*e7efe135SRashmica Gupta     }
125*e7efe135SRashmica Gupta     return std::numeric_limits<U>::quiet_NaN();
126*e7efe135SRashmica Gupta }
127*e7efe135SRashmica Gupta 
128*e7efe135SRashmica Gupta bool isCalculationType(const std::string& interface)
129*e7efe135SRashmica Gupta {
130*e7efe135SRashmica Gupta     auto itr = std::find(calculationIfaces.begin(), calculationIfaces.end(),
131*e7efe135SRashmica Gupta                          interface);
132*e7efe135SRashmica Gupta     if (itr != calculationIfaces.end())
133*e7efe135SRashmica Gupta     {
134*e7efe135SRashmica Gupta         return true;
135*e7efe135SRashmica Gupta     }
136*e7efe135SRashmica Gupta     return false;
137*e7efe135SRashmica Gupta }
138*e7efe135SRashmica Gupta 
139*e7efe135SRashmica Gupta const std::string getThresholdType(const std::string& direction,
140*e7efe135SRashmica Gupta                                    uint64_t severity)
141*e7efe135SRashmica Gupta {
142*e7efe135SRashmica Gupta     std::string threshold;
143*e7efe135SRashmica Gupta     std::string suffix;
144*e7efe135SRashmica Gupta     static const std::array thresholdTypes{"Warning", "Critical",
145*e7efe135SRashmica Gupta                                            "PerformanceLoss", "SoftShutdown",
146*e7efe135SRashmica Gupta                                            "HardShutdown"};
147*e7efe135SRashmica Gupta 
148*e7efe135SRashmica Gupta     if (severity >= thresholdTypes.size())
149*e7efe135SRashmica Gupta     {
150*e7efe135SRashmica Gupta         throw std::invalid_argument(
151*e7efe135SRashmica Gupta             "Invalid threshold severity specified in entity manager");
152*e7efe135SRashmica Gupta     }
153*e7efe135SRashmica Gupta     threshold = thresholdTypes[severity];
154*e7efe135SRashmica Gupta 
155*e7efe135SRashmica Gupta     if (direction == "less than")
156*e7efe135SRashmica Gupta     {
157*e7efe135SRashmica Gupta         suffix = "Low";
158*e7efe135SRashmica Gupta     }
159*e7efe135SRashmica Gupta     else if (direction == "greater than")
160*e7efe135SRashmica Gupta     {
161*e7efe135SRashmica Gupta         suffix = "High";
162*e7efe135SRashmica Gupta     }
163*e7efe135SRashmica Gupta     else
164*e7efe135SRashmica Gupta     {
165*e7efe135SRashmica Gupta         throw std::invalid_argument(
166*e7efe135SRashmica Gupta             "Invalid threshold direction specified in entity manager");
167*e7efe135SRashmica Gupta     }
168*e7efe135SRashmica Gupta     return threshold + suffix;
169*e7efe135SRashmica Gupta }
170*e7efe135SRashmica Gupta 
171*e7efe135SRashmica Gupta void parseThresholds(Json& thresholds, const PropertyMap& propertyMap)
172*e7efe135SRashmica Gupta {
173*e7efe135SRashmica Gupta     std::string direction;
174*e7efe135SRashmica Gupta 
175*e7efe135SRashmica Gupta     auto severity =
176*e7efe135SRashmica Gupta         getNumberFromConfig<uint64_t>(propertyMap, "Severity", true);
177*e7efe135SRashmica Gupta     auto value = getNumberFromConfig<double>(propertyMap, "Value", true);
178*e7efe135SRashmica Gupta 
179*e7efe135SRashmica Gupta     auto itr = propertyMap.find("Direction");
180*e7efe135SRashmica Gupta     if (itr != propertyMap.end())
181*e7efe135SRashmica Gupta     {
182*e7efe135SRashmica Gupta         direction = std::get<std::string>(itr->second);
183*e7efe135SRashmica Gupta     }
184*e7efe135SRashmica Gupta 
185*e7efe135SRashmica Gupta     auto threshold = getThresholdType(direction, severity);
186*e7efe135SRashmica Gupta     thresholds[threshold] = value;
187*e7efe135SRashmica Gupta }
188*e7efe135SRashmica Gupta 
189*e7efe135SRashmica Gupta void VirtualSensor::parseConfigInterface(const PropertyMap& propertyMap,
190*e7efe135SRashmica Gupta                                          const std::string& sensorType,
191*e7efe135SRashmica Gupta                                          const std::string& interface)
192*e7efe135SRashmica Gupta {
193*e7efe135SRashmica Gupta     /* Parse sensors / DBus params */
194*e7efe135SRashmica Gupta     if (auto itr = propertyMap.find("Sensors"); itr != propertyMap.end())
195*e7efe135SRashmica Gupta     {
196*e7efe135SRashmica Gupta         auto sensors = std::get<std::vector<std::string>>(itr->second);
197*e7efe135SRashmica Gupta         for (auto sensor : sensors)
198*e7efe135SRashmica Gupta         {
199*e7efe135SRashmica Gupta             std::replace(sensor.begin(), sensor.end(), ' ', '_');
200*e7efe135SRashmica Gupta             auto sensorObjPath = sensorDbusPath + sensorType + "/" + sensor;
201*e7efe135SRashmica Gupta 
202*e7efe135SRashmica Gupta             auto paramPtr =
203*e7efe135SRashmica Gupta                 std::make_unique<SensorParam>(bus, sensorObjPath, this);
204*e7efe135SRashmica Gupta             symbols.create_variable(sensor);
205*e7efe135SRashmica Gupta             paramMap.emplace(std::move(sensor), std::move(paramPtr));
206*e7efe135SRashmica Gupta         }
207*e7efe135SRashmica Gupta     }
208*e7efe135SRashmica Gupta     /* Get expression string */
209*e7efe135SRashmica Gupta     if (!isCalculationType(interface))
210*e7efe135SRashmica Gupta     {
211*e7efe135SRashmica Gupta         throw std::invalid_argument("Invalid expression in interface");
212*e7efe135SRashmica Gupta     }
213*e7efe135SRashmica Gupta     exprStr = interface;
214*e7efe135SRashmica Gupta 
215*e7efe135SRashmica Gupta     /* Get optional min and max input and output values */
216*e7efe135SRashmica Gupta     ValueIface::maxValue(
217*e7efe135SRashmica Gupta         getNumberFromConfig<double>(propertyMap, "MaxValue", false));
218*e7efe135SRashmica Gupta     ValueIface::minValue(
219*e7efe135SRashmica Gupta         getNumberFromConfig<double>(propertyMap, "MinValue", false));
220*e7efe135SRashmica Gupta     maxValidInput =
221*e7efe135SRashmica Gupta         getNumberFromConfig<double>(propertyMap, "MaxValidInput", false);
222*e7efe135SRashmica Gupta     minValidInput =
223*e7efe135SRashmica Gupta         getNumberFromConfig<double>(propertyMap, "MinValidInput", false);
224*e7efe135SRashmica Gupta }
225*e7efe135SRashmica Gupta 
226ce675228SMatt Spinler void VirtualSensor::initVirtualSensor(const Json& sensorConfig,
227ce675228SMatt Spinler                                       const std::string& objPath)
228abcc94faSVijay Khemka {
229abcc94faSVijay Khemka 
230abcc94faSVijay Khemka     static const Json empty{};
231abcc94faSVijay Khemka 
232abcc94faSVijay Khemka     /* Get threshold values if defined in config */
233abcc94faSVijay Khemka     auto threshold = sensorConfig.value("Threshold", empty);
234f15189e3SMatt Spinler 
2353e99919bSRashmica Gupta     createThresholds(threshold, objPath);
236abcc94faSVijay Khemka 
237f6443742SHarvey Wu     /* Get MaxValue, MinValue setting if defined in config */
238f6443742SHarvey Wu     auto confDesc = sensorConfig.value("Desc", empty);
239f6443742SHarvey Wu     if (auto maxConf = confDesc.find("MaxValue");
240f6443742SHarvey Wu         maxConf != confDesc.end() && maxConf->is_number())
241f6443742SHarvey Wu     {
242f6443742SHarvey Wu         ValueIface::maxValue(maxConf->get<double>());
243f6443742SHarvey Wu     }
244f6443742SHarvey Wu     if (auto minConf = confDesc.find("MinValue");
245f6443742SHarvey Wu         minConf != confDesc.end() && minConf->is_number())
246f6443742SHarvey Wu     {
247f6443742SHarvey Wu         ValueIface::minValue(minConf->get<double>());
248f6443742SHarvey Wu     }
249f6443742SHarvey Wu 
2500fcf0e1cSLei YU     /* Get optional association */
2510fcf0e1cSLei YU     auto assocJson = sensorConfig.value("Associations", empty);
2520fcf0e1cSLei YU     if (!assocJson.empty())
2530fcf0e1cSLei YU     {
2540fcf0e1cSLei YU         auto assocs = getAssociationsFromJson(assocJson);
2550fcf0e1cSLei YU         if (!assocs.empty())
2560fcf0e1cSLei YU         {
2570fcf0e1cSLei YU             associationIface =
2580fcf0e1cSLei YU                 std::make_unique<AssociationObject>(bus, objPath.c_str());
2590fcf0e1cSLei YU             associationIface->associations(assocs);
2600fcf0e1cSLei YU         }
2610fcf0e1cSLei YU     }
2620fcf0e1cSLei YU 
263abcc94faSVijay Khemka     /* Get expression string */
264abcc94faSVijay Khemka     exprStr = sensorConfig.value("Expression", "");
265abcc94faSVijay Khemka 
266abcc94faSVijay Khemka     /* Get all the parameter listed in configuration */
267abcc94faSVijay Khemka     auto params = sensorConfig.value("Params", empty);
268abcc94faSVijay Khemka 
269abcc94faSVijay Khemka     /* Check for constant parameter */
270abcc94faSVijay Khemka     const auto& consParams = params.value("ConstParam", empty);
271abcc94faSVijay Khemka     if (!consParams.empty())
272abcc94faSVijay Khemka     {
273abcc94faSVijay Khemka         for (auto& j : consParams)
274abcc94faSVijay Khemka         {
275abcc94faSVijay Khemka             if (j.find("ParamName") != j.end())
276abcc94faSVijay Khemka             {
277abcc94faSVijay Khemka                 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
2783ed9a516SVijay Khemka                 std::string name = j["ParamName"];
2793ed9a516SVijay Khemka                 symbols.create_variable(name);
2803ed9a516SVijay Khemka                 paramMap.emplace(std::move(name), std::move(paramPtr));
281abcc94faSVijay Khemka             }
282abcc94faSVijay Khemka             else
283abcc94faSVijay Khemka             {
284abcc94faSVijay Khemka                 /* Invalid configuration */
285abcc94faSVijay Khemka                 throw std::invalid_argument(
286abcc94faSVijay Khemka                     "ParamName not found in configuration");
287abcc94faSVijay Khemka             }
288abcc94faSVijay Khemka         }
289abcc94faSVijay Khemka     }
290abcc94faSVijay Khemka 
2917452a867SVijay Khemka     /* Check for dbus parameter */
2927452a867SVijay Khemka     auto dbusParams = params.value("DbusParam", empty);
2937452a867SVijay Khemka     if (!dbusParams.empty())
2947452a867SVijay Khemka     {
2957452a867SVijay Khemka         for (auto& j : dbusParams)
2967452a867SVijay Khemka         {
2977452a867SVijay Khemka             /* Get parameter dbus sensor descriptor */
2987452a867SVijay Khemka             auto desc = j.value("Desc", empty);
2997452a867SVijay Khemka             if ((!desc.empty()) && (j.find("ParamName") != j.end()))
3007452a867SVijay Khemka             {
3017452a867SVijay Khemka                 std::string sensorType = desc.value("SensorType", "");
3027452a867SVijay Khemka                 std::string name = desc.value("Name", "");
3037452a867SVijay Khemka 
3047452a867SVijay Khemka                 if (!sensorType.empty() && !name.empty())
3057452a867SVijay Khemka                 {
3067452a867SVijay Khemka                     std::string objPath(sensorDbusPath);
3077452a867SVijay Khemka                     objPath += sensorType + "/" + name;
3087452a867SVijay Khemka 
30951f898e2SVijay Khemka                     auto paramPtr =
31051f898e2SVijay Khemka                         std::make_unique<SensorParam>(bus, objPath, this);
3113ed9a516SVijay Khemka                     std::string name = j["ParamName"];
3123ed9a516SVijay Khemka                     symbols.create_variable(name);
3133ed9a516SVijay Khemka                     paramMap.emplace(std::move(name), std::move(paramPtr));
3147452a867SVijay Khemka                 }
3157452a867SVijay Khemka             }
3167452a867SVijay Khemka         }
3177452a867SVijay Khemka     }
318abcc94faSVijay Khemka 
3193ed9a516SVijay Khemka     symbols.add_constants();
3209f1ef4f5SMatt Spinler     symbols.add_package(vecopsPackage);
3213ed9a516SVijay Khemka     expression.register_symbol_table(symbols);
3223ed9a516SVijay Khemka 
3233ed9a516SVijay Khemka     /* parser from exprtk */
3243ed9a516SVijay Khemka     exprtk::parser<double> parser{};
325ddc6dcd6SMatt Spinler     if (!parser.compile(exprStr, expression))
326ddc6dcd6SMatt Spinler     {
327ddc6dcd6SMatt Spinler         log<level::ERR>("Expression compilation failed");
328ddc6dcd6SMatt Spinler 
329ddc6dcd6SMatt Spinler         for (std::size_t i = 0; i < parser.error_count(); ++i)
330ddc6dcd6SMatt Spinler         {
331ddc6dcd6SMatt Spinler             auto error = parser.get_error(i);
332ddc6dcd6SMatt Spinler 
333ddc6dcd6SMatt Spinler             log<level::ERR>(
334ddc6dcd6SMatt Spinler                 fmt::format(
335ddc6dcd6SMatt Spinler                     "Position: {} Type: {} Message: {}", error.token.position,
336ddc6dcd6SMatt Spinler                     exprtk::parser_error::to_str(error.mode), error.diagnostic)
337ddc6dcd6SMatt Spinler                     .c_str());
338ddc6dcd6SMatt Spinler         }
339ddc6dcd6SMatt Spinler         throw std::runtime_error("Expression compilation failed");
340ddc6dcd6SMatt Spinler     }
3413ed9a516SVijay Khemka 
342abcc94faSVijay Khemka     /* Print all parameters for debug purpose only */
343abcc94faSVijay Khemka     if (DEBUG)
344abcc94faSVijay Khemka         printParams(paramMap);
345abcc94faSVijay Khemka }
346abcc94faSVijay Khemka 
347*e7efe135SRashmica Gupta void VirtualSensor::initVirtualSensor(const InterfaceMap& interfaceMap,
348*e7efe135SRashmica Gupta                                       const std::string& objPath,
349*e7efe135SRashmica Gupta                                       const std::string& sensorType,
350*e7efe135SRashmica Gupta                                       const std::string& calculationIface)
351*e7efe135SRashmica Gupta {
352*e7efe135SRashmica Gupta     Json thresholds;
353*e7efe135SRashmica Gupta     const std::string vsThresholdsIntf =
354*e7efe135SRashmica Gupta         calculationIface + vsThresholdsIfaceSuffix;
355*e7efe135SRashmica Gupta 
356*e7efe135SRashmica Gupta     for (const auto& [interface, propertyMap] : interfaceMap)
357*e7efe135SRashmica Gupta     {
358*e7efe135SRashmica Gupta         /* Each threshold is on it's own interface with a number as a suffix
359*e7efe135SRashmica Gupta          * eg xyz.openbmc_project.Configuration.ModifiedMedian.Thresholds1 */
360*e7efe135SRashmica Gupta         if (interface.find(vsThresholdsIntf) != std::string::npos)
361*e7efe135SRashmica Gupta         {
362*e7efe135SRashmica Gupta             parseThresholds(thresholds, propertyMap);
363*e7efe135SRashmica Gupta         }
364*e7efe135SRashmica Gupta         else if (interface == calculationIface)
365*e7efe135SRashmica Gupta         {
366*e7efe135SRashmica Gupta             parseConfigInterface(propertyMap, sensorType, interface);
367*e7efe135SRashmica Gupta         }
368*e7efe135SRashmica Gupta     }
369*e7efe135SRashmica Gupta 
370*e7efe135SRashmica Gupta     createThresholds(thresholds, objPath);
371*e7efe135SRashmica Gupta     symbols.add_constants();
372*e7efe135SRashmica Gupta     symbols.add_package(vecopsPackage);
373*e7efe135SRashmica Gupta     expression.register_symbol_table(symbols);
374*e7efe135SRashmica Gupta 
375*e7efe135SRashmica Gupta     /* Print all parameters for debug purpose only */
376*e7efe135SRashmica Gupta     if (DEBUG)
377*e7efe135SRashmica Gupta     {
378*e7efe135SRashmica Gupta         printParams(paramMap);
379*e7efe135SRashmica Gupta     }
380*e7efe135SRashmica Gupta }
381*e7efe135SRashmica Gupta 
382abcc94faSVijay Khemka void VirtualSensor::setSensorValue(double value)
383abcc94faSVijay Khemka {
384543bf668SPatrick Williams     value = std::clamp(value, ValueIface::minValue(), ValueIface::maxValue());
385abcc94faSVijay Khemka     ValueIface::value(value);
386abcc94faSVijay Khemka }
387abcc94faSVijay Khemka 
388*e7efe135SRashmica Gupta double VirtualSensor::calculateValue()
389*e7efe135SRashmica Gupta {
390*e7efe135SRashmica Gupta     // Placeholder until calculation types are added
391*e7efe135SRashmica Gupta     return std::numeric_limits<double>::quiet_NaN();
392*e7efe135SRashmica Gupta }
393*e7efe135SRashmica Gupta 
394abcc94faSVijay Khemka void VirtualSensor::updateVirtualSensor()
3953ed9a516SVijay Khemka {
3963ed9a516SVijay Khemka     for (auto& param : paramMap)
3973ed9a516SVijay Khemka     {
3983ed9a516SVijay Khemka         auto& name = param.first;
3993ed9a516SVijay Khemka         auto& data = param.second;
4003ed9a516SVijay Khemka         if (auto var = symbols.get_variable(name))
4013ed9a516SVijay Khemka         {
4023ed9a516SVijay Khemka             var->ref() = data->getParamValue();
4033ed9a516SVijay Khemka         }
4043ed9a516SVijay Khemka         else
4053ed9a516SVijay Khemka         {
4063ed9a516SVijay Khemka             /* Invalid parameter */
4073ed9a516SVijay Khemka             throw std::invalid_argument("ParamName not found in symbols");
4083ed9a516SVijay Khemka         }
4093ed9a516SVijay Khemka     }
410*e7efe135SRashmica Gupta     auto itr =
411*e7efe135SRashmica Gupta         std::find(calculationIfaces.begin(), calculationIfaces.end(), exprStr);
412*e7efe135SRashmica Gupta     auto val = (itr == calculationIfaces.end()) ? expression.value()
413*e7efe135SRashmica Gupta                                                 : calculateValue();
41432a7156bSVijay Khemka 
41532a7156bSVijay Khemka     /* Set sensor value to dbus interface */
4163ed9a516SVijay Khemka     setSensorValue(val);
41732a7156bSVijay Khemka 
4183ed9a516SVijay Khemka     if (DEBUG)
419*e7efe135SRashmica Gupta     {
4203ed9a516SVijay Khemka         std::cout << "Sensor value is " << val << "\n";
421*e7efe135SRashmica Gupta     }
42232a7156bSVijay Khemka 
4238f5e6119SMatt Spinler     /* Check sensor thresholds and log required message */
424b306b03dSMatt Spinler     checkThresholds(val, perfLossIface);
425fdb826d5SPatrick Williams     checkThresholds(val, warningIface);
426fdb826d5SPatrick Williams     checkThresholds(val, criticalIface);
427fdb826d5SPatrick Williams     checkThresholds(val, softShutdownIface);
428fdb826d5SPatrick Williams     checkThresholds(val, hardShutdownIface);
4293ed9a516SVijay Khemka }
430abcc94faSVijay Khemka 
4313e99919bSRashmica Gupta void VirtualSensor::createThresholds(const Json& threshold,
4323e99919bSRashmica Gupta                                      const std::string& objPath)
4333e99919bSRashmica Gupta {
4343e99919bSRashmica Gupta     if (threshold.empty())
4353e99919bSRashmica Gupta     {
4363e99919bSRashmica Gupta         return;
4373e99919bSRashmica Gupta     }
4383e99919bSRashmica Gupta     // Only create the threshold interfaces if
4393e99919bSRashmica Gupta     // at least one of their values is present.
4403e99919bSRashmica Gupta     if (threshold.contains("CriticalHigh") || threshold.contains("CriticalLow"))
4413e99919bSRashmica Gupta     {
4423e99919bSRashmica Gupta         criticalIface =
4433e99919bSRashmica Gupta             std::make_unique<Threshold<CriticalObject>>(bus, objPath.c_str());
4443e99919bSRashmica Gupta 
4453e99919bSRashmica Gupta         criticalIface->criticalHigh(threshold.value(
4463e99919bSRashmica Gupta             "CriticalHigh", std::numeric_limits<double>::quiet_NaN()));
4473e99919bSRashmica Gupta         criticalIface->criticalLow(threshold.value(
4483e99919bSRashmica Gupta             "CriticalLow", std::numeric_limits<double>::quiet_NaN()));
4493e99919bSRashmica Gupta     }
4503e99919bSRashmica Gupta 
4513e99919bSRashmica Gupta     if (threshold.contains("WarningHigh") || threshold.contains("WarningLow"))
4523e99919bSRashmica Gupta     {
4533e99919bSRashmica Gupta         warningIface =
4543e99919bSRashmica Gupta             std::make_unique<Threshold<WarningObject>>(bus, objPath.c_str());
4553e99919bSRashmica Gupta 
4563e99919bSRashmica Gupta         warningIface->warningHigh(threshold.value(
4573e99919bSRashmica Gupta             "WarningHigh", std::numeric_limits<double>::quiet_NaN()));
4583e99919bSRashmica Gupta         warningIface->warningLow(threshold.value(
4593e99919bSRashmica Gupta             "WarningLow", std::numeric_limits<double>::quiet_NaN()));
4603e99919bSRashmica Gupta     }
4613e99919bSRashmica Gupta 
4623e99919bSRashmica Gupta     if (threshold.contains("HardShutdownHigh") ||
4633e99919bSRashmica Gupta         threshold.contains("HardShutdownLow"))
4643e99919bSRashmica Gupta     {
4653e99919bSRashmica Gupta         hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>(
4663e99919bSRashmica Gupta             bus, objPath.c_str());
4673e99919bSRashmica Gupta 
4683e99919bSRashmica Gupta         hardShutdownIface->hardShutdownHigh(threshold.value(
4693e99919bSRashmica Gupta             "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
4703e99919bSRashmica Gupta         hardShutdownIface->hardShutdownLow(threshold.value(
4713e99919bSRashmica Gupta             "HardShutdownLow", std::numeric_limits<double>::quiet_NaN()));
4723e99919bSRashmica Gupta     }
4733e99919bSRashmica Gupta 
4743e99919bSRashmica Gupta     if (threshold.contains("SoftShutdownHigh") ||
4753e99919bSRashmica Gupta         threshold.contains("SoftShutdownLow"))
4763e99919bSRashmica Gupta     {
4773e99919bSRashmica Gupta         softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>(
4783e99919bSRashmica Gupta             bus, objPath.c_str());
4793e99919bSRashmica Gupta 
4803e99919bSRashmica Gupta         softShutdownIface->softShutdownHigh(threshold.value(
4813e99919bSRashmica Gupta             "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
4823e99919bSRashmica Gupta         softShutdownIface->softShutdownLow(threshold.value(
4833e99919bSRashmica Gupta             "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN()));
4843e99919bSRashmica Gupta     }
4853e99919bSRashmica Gupta 
4863e99919bSRashmica Gupta     if (threshold.contains("PerformanceLossHigh") ||
4873e99919bSRashmica Gupta         threshold.contains("PerformanceLossLow"))
4883e99919bSRashmica Gupta     {
4893e99919bSRashmica Gupta         perfLossIface = std::make_unique<Threshold<PerformanceLossObject>>(
4903e99919bSRashmica Gupta             bus, objPath.c_str());
4913e99919bSRashmica Gupta 
4923e99919bSRashmica Gupta         perfLossIface->performanceLossHigh(threshold.value(
4933e99919bSRashmica Gupta             "PerformanceLossHigh", std::numeric_limits<double>::quiet_NaN()));
4943e99919bSRashmica Gupta         perfLossIface->performanceLossLow(threshold.value(
4953e99919bSRashmica Gupta             "PerformanceLossLow", std::numeric_limits<double>::quiet_NaN()));
4963e99919bSRashmica Gupta     }
4973e99919bSRashmica Gupta }
4983e99919bSRashmica Gupta 
499*e7efe135SRashmica Gupta ManagedObjectType VirtualSensors::getObjectsFromDBus()
500*e7efe135SRashmica Gupta {
501*e7efe135SRashmica Gupta     ManagedObjectType objects;
502*e7efe135SRashmica Gupta 
503*e7efe135SRashmica Gupta     try
504*e7efe135SRashmica Gupta     {
505*e7efe135SRashmica Gupta         auto method = bus.new_method_call(entityManagerBusName, "/",
506*e7efe135SRashmica Gupta                                           "org.freedesktop.DBus.ObjectManager",
507*e7efe135SRashmica Gupta                                           "GetManagedObjects");
508*e7efe135SRashmica Gupta         auto reply = bus.call(method);
509*e7efe135SRashmica Gupta         reply.read(objects);
510*e7efe135SRashmica Gupta     }
511*e7efe135SRashmica Gupta     catch (const sdbusplus::exception::SdBusError& ex)
512*e7efe135SRashmica Gupta     {
513*e7efe135SRashmica Gupta         // If entity manager isn't running yet, keep going.
514*e7efe135SRashmica Gupta         if (std::string("org.freedesktop.DBus.Error.ServiceUnknown") !=
515*e7efe135SRashmica Gupta             ex.name())
516*e7efe135SRashmica Gupta         {
517*e7efe135SRashmica Gupta             throw ex.name();
518*e7efe135SRashmica Gupta         }
519*e7efe135SRashmica Gupta     }
520*e7efe135SRashmica Gupta 
521*e7efe135SRashmica Gupta     return objects;
522*e7efe135SRashmica Gupta }
523*e7efe135SRashmica Gupta 
524*e7efe135SRashmica Gupta void VirtualSensors::propertiesChanged(sdbusplus::message::message& msg)
525*e7efe135SRashmica Gupta {
526*e7efe135SRashmica Gupta     std::string path;
527*e7efe135SRashmica Gupta     PropertyMap properties;
528*e7efe135SRashmica Gupta 
529*e7efe135SRashmica Gupta     msg.read(path, properties);
530*e7efe135SRashmica Gupta 
531*e7efe135SRashmica Gupta     /* We get multiple callbacks for one sensor. 'Type' is a required field and
532*e7efe135SRashmica Gupta      * is a unique label so use to to only proceed once per sensor */
533*e7efe135SRashmica Gupta     if (properties.contains("Type"))
534*e7efe135SRashmica Gupta     {
535*e7efe135SRashmica Gupta         if (isCalculationType(path))
536*e7efe135SRashmica Gupta         {
537*e7efe135SRashmica Gupta             createVirtualSensorsFromDBus(path);
538*e7efe135SRashmica Gupta         }
539*e7efe135SRashmica Gupta     }
540*e7efe135SRashmica Gupta }
541*e7efe135SRashmica Gupta 
542abcc94faSVijay Khemka /** @brief Parsing Virtual Sensor config JSON file  */
543abcc94faSVijay Khemka Json VirtualSensors::parseConfigFile(const std::string configFile)
544abcc94faSVijay Khemka {
545abcc94faSVijay Khemka     std::ifstream jsonFile(configFile);
546abcc94faSVijay Khemka     if (!jsonFile.is_open())
547abcc94faSVijay Khemka     {
548abcc94faSVijay Khemka         log<level::ERR>("config JSON file not found",
549abcc94faSVijay Khemka                         entry("FILENAME=%s", configFile.c_str()));
550*e7efe135SRashmica Gupta         return {};
551abcc94faSVijay Khemka     }
552abcc94faSVijay Khemka 
553abcc94faSVijay Khemka     auto data = Json::parse(jsonFile, nullptr, false);
554abcc94faSVijay Khemka     if (data.is_discarded())
555abcc94faSVijay Khemka     {
556abcc94faSVijay Khemka         log<level::ERR>("config readings JSON parser failure",
557abcc94faSVijay Khemka                         entry("FILENAME=%s", configFile.c_str()));
558abcc94faSVijay Khemka         throw std::exception{};
559abcc94faSVijay Khemka     }
560abcc94faSVijay Khemka 
561abcc94faSVijay Khemka     return data;
562abcc94faSVijay Khemka }
563abcc94faSVijay Khemka 
564e0d371e4SVijay Khemka std::map<std::string, ValueIface::Unit> unitMap = {
565e0d371e4SVijay Khemka     {"temperature", ValueIface::Unit::DegreesC},
566e0d371e4SVijay Khemka     {"fan_tach", ValueIface::Unit::RPMS},
567e0d371e4SVijay Khemka     {"voltage", ValueIface::Unit::Volts},
568e0d371e4SVijay Khemka     {"altitude", ValueIface::Unit::Meters},
569e0d371e4SVijay Khemka     {"current", ValueIface::Unit::Amperes},
570e0d371e4SVijay Khemka     {"power", ValueIface::Unit::Watts},
571e0d371e4SVijay Khemka     {"energy", ValueIface::Unit::Joules},
5722b56ddb3SKumar Thangavel     {"utilization", ValueIface::Unit::Percent},
5734ac7a7f2SRashmica Gupta     {"airflow", ValueIface::Unit::CFM},
5744ac7a7f2SRashmica Gupta     {"pressure", ValueIface::Unit::Pascals}};
575e0d371e4SVijay Khemka 
576*e7efe135SRashmica Gupta const std::string getSensorTypeFromUnit(const std::string& unit)
577*e7efe135SRashmica Gupta {
578*e7efe135SRashmica Gupta     std::string unitPrefix = "xyz.openbmc_project.Sensor.Value.Unit.";
579*e7efe135SRashmica Gupta     for (auto [type, unitObj] : unitMap)
580*e7efe135SRashmica Gupta     {
581*e7efe135SRashmica Gupta         auto unitPath = ValueIface::convertUnitToString(unitObj);
582*e7efe135SRashmica Gupta         if (unitPath == (unitPrefix + unit))
583*e7efe135SRashmica Gupta         {
584*e7efe135SRashmica Gupta             return type;
585*e7efe135SRashmica Gupta         }
586*e7efe135SRashmica Gupta     }
587*e7efe135SRashmica Gupta     return "";
588*e7efe135SRashmica Gupta }
589*e7efe135SRashmica Gupta 
590*e7efe135SRashmica Gupta void VirtualSensors::setupMatches()
591*e7efe135SRashmica Gupta {
592*e7efe135SRashmica Gupta     /* Already setup */
593*e7efe135SRashmica Gupta     if (!this->matches.empty())
594*e7efe135SRashmica Gupta     {
595*e7efe135SRashmica Gupta         return;
596*e7efe135SRashmica Gupta     }
597*e7efe135SRashmica Gupta 
598*e7efe135SRashmica Gupta     /* Setup matches */
599*e7efe135SRashmica Gupta     auto eventHandler = [this](sdbusplus::message::message& message) {
600*e7efe135SRashmica Gupta         if (message.is_method_error())
601*e7efe135SRashmica Gupta         {
602*e7efe135SRashmica Gupta             log<level::ERR>("Callback method error");
603*e7efe135SRashmica Gupta             return;
604*e7efe135SRashmica Gupta         }
605*e7efe135SRashmica Gupta         this->propertiesChanged(message);
606*e7efe135SRashmica Gupta     };
607*e7efe135SRashmica Gupta 
608*e7efe135SRashmica Gupta     for (const char* iface : calculationIfaces)
609*e7efe135SRashmica Gupta     {
610*e7efe135SRashmica Gupta         auto match = std::make_unique<sdbusplus::bus::match::match>(
611*e7efe135SRashmica Gupta             bus,
612*e7efe135SRashmica Gupta             sdbusplus::bus::match::rules::propertiesChangedNamespace(
613*e7efe135SRashmica Gupta                 "/xyz/openbmc_project/inventory", iface),
614*e7efe135SRashmica Gupta             eventHandler);
615*e7efe135SRashmica Gupta         this->matches.emplace_back(std::move(match));
616*e7efe135SRashmica Gupta     }
617*e7efe135SRashmica Gupta }
618*e7efe135SRashmica Gupta 
619*e7efe135SRashmica Gupta void VirtualSensors::createVirtualSensorsFromDBus(
620*e7efe135SRashmica Gupta     const std::string& calculationIface)
621*e7efe135SRashmica Gupta {
622*e7efe135SRashmica Gupta     if (calculationIface.empty())
623*e7efe135SRashmica Gupta     {
624*e7efe135SRashmica Gupta         log<level::ERR>("No calculation type supplied");
625*e7efe135SRashmica Gupta         return;
626*e7efe135SRashmica Gupta     }
627*e7efe135SRashmica Gupta     auto objects = getObjectsFromDBus();
628*e7efe135SRashmica Gupta 
629*e7efe135SRashmica Gupta     /* Get virtual sensors config data */
630*e7efe135SRashmica Gupta     for (const auto& [path, interfaceMap] : objects)
631*e7efe135SRashmica Gupta     {
632*e7efe135SRashmica Gupta         auto objpath = static_cast<std::string>(path);
633*e7efe135SRashmica Gupta         std::string name = path.filename();
634*e7efe135SRashmica Gupta         std::string sensorType, sensorUnit;
635*e7efe135SRashmica Gupta 
636*e7efe135SRashmica Gupta         /* Find Virtual Sensor interfaces */
637*e7efe135SRashmica Gupta         if (!interfaceMap.contains(calculationIface))
638*e7efe135SRashmica Gupta         {
639*e7efe135SRashmica Gupta             continue;
640*e7efe135SRashmica Gupta         }
641*e7efe135SRashmica Gupta         if (name.empty())
642*e7efe135SRashmica Gupta         {
643*e7efe135SRashmica Gupta             log<level::ERR>(
644*e7efe135SRashmica Gupta                 "Virtual Sensor name not found in entity manager config");
645*e7efe135SRashmica Gupta             continue;
646*e7efe135SRashmica Gupta         }
647*e7efe135SRashmica Gupta         if (virtualSensorsMap.contains(name))
648*e7efe135SRashmica Gupta         {
649*e7efe135SRashmica Gupta             log<level::ERR>("A virtual sensor with this name already exists",
650*e7efe135SRashmica Gupta                             entry("NAME=%s", name.c_str()));
651*e7efe135SRashmica Gupta             continue;
652*e7efe135SRashmica Gupta         }
653*e7efe135SRashmica Gupta 
654*e7efe135SRashmica Gupta         /* Extract the virtual sensor type as we need this to initialize the
655*e7efe135SRashmica Gupta          * sensor */
656*e7efe135SRashmica Gupta         for (const auto& [interface, propertyMap] : interfaceMap)
657*e7efe135SRashmica Gupta         {
658*e7efe135SRashmica Gupta             if (interface != calculationIface)
659*e7efe135SRashmica Gupta             {
660*e7efe135SRashmica Gupta                 continue;
661*e7efe135SRashmica Gupta             }
662*e7efe135SRashmica Gupta             auto itr = propertyMap.find("Units");
663*e7efe135SRashmica Gupta             if (itr != propertyMap.end())
664*e7efe135SRashmica Gupta             {
665*e7efe135SRashmica Gupta                 sensorUnit = std::get<std::string>(itr->second);
666*e7efe135SRashmica Gupta                 break;
667*e7efe135SRashmica Gupta             }
668*e7efe135SRashmica Gupta         }
669*e7efe135SRashmica Gupta         sensorType = getSensorTypeFromUnit(sensorUnit);
670*e7efe135SRashmica Gupta         if (sensorType.empty())
671*e7efe135SRashmica Gupta         {
672*e7efe135SRashmica Gupta             log<level::ERR>("Sensor unit is not supported",
673*e7efe135SRashmica Gupta                             entry("TYPE=%s", sensorUnit.c_str()));
674*e7efe135SRashmica Gupta             continue;
675*e7efe135SRashmica Gupta         }
676*e7efe135SRashmica Gupta 
677*e7efe135SRashmica Gupta         try
678*e7efe135SRashmica Gupta         {
679*e7efe135SRashmica Gupta             auto virtObjPath = sensorDbusPath + sensorType + "/" + name;
680*e7efe135SRashmica Gupta 
681*e7efe135SRashmica Gupta             auto virtualSensorPtr = std::make_unique<VirtualSensor>(
682*e7efe135SRashmica Gupta                 bus, virtObjPath.c_str(), interfaceMap, name, sensorType,
683*e7efe135SRashmica Gupta                 calculationIface);
684*e7efe135SRashmica Gupta             log<level::INFO>("Added a new virtual sensor",
685*e7efe135SRashmica Gupta                              entry("NAME=%s", name.c_str()));
686*e7efe135SRashmica Gupta             virtualSensorPtr->updateVirtualSensor();
687*e7efe135SRashmica Gupta 
688*e7efe135SRashmica Gupta             /* Initialize unit value for virtual sensor */
689*e7efe135SRashmica Gupta             virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
690*e7efe135SRashmica Gupta             virtualSensorPtr->emit_object_added();
691*e7efe135SRashmica Gupta 
692*e7efe135SRashmica Gupta             virtualSensorsMap.emplace(name, std::move(virtualSensorPtr));
693*e7efe135SRashmica Gupta 
694*e7efe135SRashmica Gupta             /* Setup match for interfaces removed */
695*e7efe135SRashmica Gupta             auto intfRemoved = [this, objpath,
696*e7efe135SRashmica Gupta                                 name](sdbusplus::message::message& message) {
697*e7efe135SRashmica Gupta                 if (!virtualSensorsMap.contains(name))
698*e7efe135SRashmica Gupta                 {
699*e7efe135SRashmica Gupta                     return;
700*e7efe135SRashmica Gupta                 }
701*e7efe135SRashmica Gupta                 sdbusplus::message::object_path path;
702*e7efe135SRashmica Gupta                 message.read(path);
703*e7efe135SRashmica Gupta                 if (static_cast<const std::string&>(path) == objpath)
704*e7efe135SRashmica Gupta                 {
705*e7efe135SRashmica Gupta                     log<level::INFO>("Removed a virtual sensor",
706*e7efe135SRashmica Gupta                                      entry("NAME=%s", name.c_str()));
707*e7efe135SRashmica Gupta                     virtualSensorsMap.erase(name);
708*e7efe135SRashmica Gupta                 }
709*e7efe135SRashmica Gupta             };
710*e7efe135SRashmica Gupta             auto matchOnRemove = std::make_unique<sdbusplus::bus::match::match>(
711*e7efe135SRashmica Gupta                 bus,
712*e7efe135SRashmica Gupta                 sdbusplus::bus::match::rules::interfacesRemoved() +
713*e7efe135SRashmica Gupta                     sdbusplus::bus::match::rules::argNpath(0, objpath),
714*e7efe135SRashmica Gupta                 intfRemoved);
715*e7efe135SRashmica Gupta             /* TODO: slight race condition here. Check that the config still
716*e7efe135SRashmica Gupta              * exists */
717*e7efe135SRashmica Gupta             this->matches.emplace_back(std::move(matchOnRemove));
718*e7efe135SRashmica Gupta         }
719*e7efe135SRashmica Gupta         catch (std::invalid_argument& ia)
720*e7efe135SRashmica Gupta         {
721*e7efe135SRashmica Gupta             log<level::ERR>("Failed to set up virtual sensor",
722*e7efe135SRashmica Gupta                             entry("Error=%s", ia.what()));
723*e7efe135SRashmica Gupta         }
724*e7efe135SRashmica Gupta     }
725*e7efe135SRashmica Gupta }
726*e7efe135SRashmica Gupta 
727abcc94faSVijay Khemka void VirtualSensors::createVirtualSensors()
728abcc94faSVijay Khemka {
729abcc94faSVijay Khemka     static const Json empty{};
730abcc94faSVijay Khemka 
731abcc94faSVijay Khemka     auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
732*e7efe135SRashmica Gupta 
733abcc94faSVijay Khemka     // print values
734abcc94faSVijay Khemka     if (DEBUG)
735*e7efe135SRashmica Gupta     {
736abcc94faSVijay Khemka         std::cout << "Config json data:\n" << data << "\n\n";
737*e7efe135SRashmica Gupta     }
738abcc94faSVijay Khemka 
739abcc94faSVijay Khemka     /* Get virtual sensors  config data */
740abcc94faSVijay Khemka     for (const auto& j : data)
741abcc94faSVijay Khemka     {
742abcc94faSVijay Khemka         auto desc = j.value("Desc", empty);
743abcc94faSVijay Khemka         if (!desc.empty())
744abcc94faSVijay Khemka         {
745*e7efe135SRashmica Gupta             if (desc.value("Config", "") == "D-Bus")
746*e7efe135SRashmica Gupta             {
747*e7efe135SRashmica Gupta                 /* Look on D-Bus for a virtual sensor config. Set up matches
748*e7efe135SRashmica Gupta                  * first because the configs may not be on D-Bus yet and we
749*e7efe135SRashmica Gupta                  * don't want to miss them */
750*e7efe135SRashmica Gupta                 setupMatches();
751*e7efe135SRashmica Gupta 
752*e7efe135SRashmica Gupta                 if (desc.contains("Type"))
753*e7efe135SRashmica Gupta                 {
754*e7efe135SRashmica Gupta                     auto path = "xyz.openbmc_project.Configuration." +
755*e7efe135SRashmica Gupta                                 desc.value("Type", "");
756*e7efe135SRashmica Gupta                     if (!isCalculationType(path))
757*e7efe135SRashmica Gupta                     {
758*e7efe135SRashmica Gupta                         log<level::ERR>(
759*e7efe135SRashmica Gupta                             "Invalid calculation type supplied\n",
760*e7efe135SRashmica Gupta                             entry("TYPE=%s", desc.value("Type", "").c_str()));
761*e7efe135SRashmica Gupta                         continue;
762*e7efe135SRashmica Gupta                     }
763*e7efe135SRashmica Gupta                     createVirtualSensorsFromDBus(path);
764*e7efe135SRashmica Gupta                 }
765*e7efe135SRashmica Gupta                 continue;
766*e7efe135SRashmica Gupta             }
767*e7efe135SRashmica Gupta 
768abcc94faSVijay Khemka             std::string sensorType = desc.value("SensorType", "");
769abcc94faSVijay Khemka             std::string name = desc.value("Name", "");
770665a0a29SRashmica Gupta             std::replace(name.begin(), name.end(), ' ', '_');
771abcc94faSVijay Khemka 
772abcc94faSVijay Khemka             if (!name.empty() && !sensorType.empty())
773abcc94faSVijay Khemka             {
774e0d371e4SVijay Khemka                 if (unitMap.find(sensorType) == unitMap.end())
775e0d371e4SVijay Khemka                 {
776e0d371e4SVijay Khemka                     log<level::ERR>("Sensor type is not supported",
777e0d371e4SVijay Khemka                                     entry("TYPE=%s", sensorType.c_str()));
778e0d371e4SVijay Khemka                 }
779e0d371e4SVijay Khemka                 else
780e0d371e4SVijay Khemka                 {
78167d8b9d2SRashmica Gupta                     if (virtualSensorsMap.find(name) != virtualSensorsMap.end())
78267d8b9d2SRashmica Gupta                     {
78367d8b9d2SRashmica Gupta                         log<level::ERR>(
78467d8b9d2SRashmica Gupta                             "A virtual sensor with this name already exists",
78567d8b9d2SRashmica Gupta                             entry("TYPE=%s", name.c_str()));
78667d8b9d2SRashmica Gupta                         continue;
78767d8b9d2SRashmica Gupta                     }
788abcc94faSVijay Khemka                     std::string objPath(sensorDbusPath);
789abcc94faSVijay Khemka                     objPath += sensorType + "/" + name;
790abcc94faSVijay Khemka 
79132a7156bSVijay Khemka                     auto virtualSensorPtr = std::make_unique<VirtualSensor>(
79232a7156bSVijay Khemka                         bus, objPath.c_str(), j, name);
793abcc94faSVijay Khemka 
794abcc94faSVijay Khemka                     log<level::INFO>("Added a new virtual sensor",
795abcc94faSVijay Khemka                                      entry("NAME=%s", name.c_str()));
7963ed9a516SVijay Khemka                     virtualSensorPtr->updateVirtualSensor();
797e0d371e4SVijay Khemka 
798e0d371e4SVijay Khemka                     /* Initialize unit value for virtual sensor */
799e0d371e4SVijay Khemka                     virtualSensorPtr->ValueIface::unit(unitMap[sensorType]);
800a2fa63a6SRashmica Gupta                     virtualSensorPtr->emit_object_added();
801e0d371e4SVijay Khemka 
8023ed9a516SVijay Khemka                     virtualSensorsMap.emplace(std::move(name),
8033ed9a516SVijay Khemka                                               std::move(virtualSensorPtr));
804abcc94faSVijay Khemka                 }
805e0d371e4SVijay Khemka             }
806abcc94faSVijay Khemka             else
807abcc94faSVijay Khemka             {
808abcc94faSVijay Khemka                 log<level::ERR>("Sensor type or name not found in config file");
809abcc94faSVijay Khemka             }
810abcc94faSVijay Khemka         }
811abcc94faSVijay Khemka         else
812abcc94faSVijay Khemka         {
813abcc94faSVijay Khemka             log<level::ERR>(
814abcc94faSVijay Khemka                 "Descriptor for new virtual sensor not found in config file");
815abcc94faSVijay Khemka         }
816abcc94faSVijay Khemka     }
817abcc94faSVijay Khemka }
818abcc94faSVijay Khemka 
819abcc94faSVijay Khemka } // namespace virtualSensor
820abcc94faSVijay Khemka } // namespace phosphor
821abcc94faSVijay Khemka 
822abcc94faSVijay Khemka /**
823abcc94faSVijay Khemka  * @brief Main
824abcc94faSVijay Khemka  */
825abcc94faSVijay Khemka int main()
826abcc94faSVijay Khemka {
827abcc94faSVijay Khemka 
828abcc94faSVijay Khemka     // Get a default event loop
829abcc94faSVijay Khemka     auto event = sdeventplus::Event::get_default();
830abcc94faSVijay Khemka 
831abcc94faSVijay Khemka     // Get a handle to system dbus
832abcc94faSVijay Khemka     auto bus = sdbusplus::bus::new_default();
833abcc94faSVijay Khemka 
8346c19e7d2SMatt Spinler     // Add the ObjectManager interface
8356c19e7d2SMatt Spinler     sdbusplus::server::manager::manager objManager(bus, "/");
8366c19e7d2SMatt Spinler 
837abcc94faSVijay Khemka     // Create an virtual sensors object
838abcc94faSVijay Khemka     phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
839abcc94faSVijay Khemka 
840abcc94faSVijay Khemka     // Request service bus name
841abcc94faSVijay Khemka     bus.request_name(busName);
842abcc94faSVijay Khemka 
843abcc94faSVijay Khemka     // Attach the bus to sd_event to service user requests
844abcc94faSVijay Khemka     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
845abcc94faSVijay Khemka     event.loop();
846abcc94faSVijay Khemka 
847abcc94faSVijay Khemka     return 0;
848abcc94faSVijay Khemka }
849