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