1abcc94faSVijay Khemka #include "virtualSensor.hpp" 2abcc94faSVijay Khemka 3abcc94faSVijay Khemka #include "config.hpp" 4abcc94faSVijay Khemka 5ddc6dcd6SMatt Spinler #include <fmt/format.h> 6ddc6dcd6SMatt Spinler 7abcc94faSVijay Khemka #include <phosphor-logging/log.hpp> 8abcc94faSVijay Khemka #include <sdeventplus/event.hpp> 9abcc94faSVijay Khemka 10abcc94faSVijay Khemka #include <fstream> 11abcc94faSVijay Khemka #include <iostream> 12abcc94faSVijay Khemka 13abcc94faSVijay Khemka static constexpr bool DEBUG = false; 14abcc94faSVijay Khemka static constexpr auto busName = "xyz.openbmc_project.VirtualSensor"; 15abcc94faSVijay Khemka static constexpr auto sensorDbusPath = "/xyz/openbmc_project/sensors/"; 16abcc94faSVijay Khemka 17abcc94faSVijay Khemka using namespace phosphor::logging; 18abcc94faSVijay Khemka 1951f898e2SVijay Khemka int handleDbusSignal(sd_bus_message* msg, void* usrData, sd_bus_error*) 2051f898e2SVijay Khemka { 2151f898e2SVijay Khemka if (usrData == nullptr) 2251f898e2SVijay Khemka { 2351f898e2SVijay Khemka throw std::runtime_error("Invalid match"); 2451f898e2SVijay Khemka } 2551f898e2SVijay Khemka 2651f898e2SVijay Khemka auto sdbpMsg = sdbusplus::message::message(msg); 2751f898e2SVijay Khemka std::string msgIfce; 2851f898e2SVijay Khemka std::map<std::string, std::variant<int64_t, double, bool>> msgData; 2951f898e2SVijay Khemka 3051f898e2SVijay Khemka sdbpMsg.read(msgIfce, msgData); 3151f898e2SVijay Khemka 3251f898e2SVijay Khemka if (msgData.find("Value") != msgData.end()) 3351f898e2SVijay Khemka { 3451f898e2SVijay Khemka using namespace phosphor::virtualSensor; 3551f898e2SVijay Khemka VirtualSensor* obj = static_cast<VirtualSensor*>(usrData); 3651f898e2SVijay Khemka // TODO(openbmc/phosphor-virtual-sensor#1): updateVirtualSensor should 3751f898e2SVijay Khemka // be changed to take the information we got from the signal, to avoid 3851f898e2SVijay Khemka // having to do numerous dbus queries. 3951f898e2SVijay Khemka obj->updateVirtualSensor(); 4051f898e2SVijay Khemka } 4151f898e2SVijay Khemka return 0; 4251f898e2SVijay Khemka } 4351f898e2SVijay Khemka 44abcc94faSVijay Khemka namespace phosphor 45abcc94faSVijay Khemka { 46abcc94faSVijay Khemka namespace virtualSensor 47abcc94faSVijay Khemka { 48abcc94faSVijay Khemka 49abcc94faSVijay Khemka void printParams(const VirtualSensor::ParamMap& paramMap) 50abcc94faSVijay Khemka { 51abcc94faSVijay Khemka for (const auto& p : paramMap) 52abcc94faSVijay Khemka { 53abcc94faSVijay Khemka const auto& p1 = p.first; 54abcc94faSVijay Khemka const auto& p2 = p.second; 55abcc94faSVijay Khemka auto val = p2->getParamValue(); 56abcc94faSVijay Khemka std::cout << p1 << " = " << val << "\n"; 57abcc94faSVijay Khemka } 58abcc94faSVijay Khemka } 59abcc94faSVijay Khemka 60abcc94faSVijay Khemka double SensorParam::getParamValue() 61abcc94faSVijay Khemka { 62abcc94faSVijay Khemka switch (paramType) 63abcc94faSVijay Khemka { 64abcc94faSVijay Khemka case constParam: 65abcc94faSVijay Khemka return value; 66abcc94faSVijay Khemka break; 677452a867SVijay Khemka case dbusParam: 687452a867SVijay Khemka return dbusSensor->getSensorValue(); 697452a867SVijay Khemka break; 70abcc94faSVijay Khemka default: 71abcc94faSVijay Khemka throw std::invalid_argument("param type not supported"); 72abcc94faSVijay Khemka } 73abcc94faSVijay Khemka } 74abcc94faSVijay Khemka 75ce675228SMatt Spinler void VirtualSensor::initVirtualSensor(const Json& sensorConfig, 76ce675228SMatt Spinler const std::string& objPath) 77abcc94faSVijay Khemka { 78abcc94faSVijay Khemka 79abcc94faSVijay Khemka static const Json empty{}; 80abcc94faSVijay Khemka 81abcc94faSVijay Khemka /* Get threshold values if defined in config */ 82abcc94faSVijay Khemka auto threshold = sensorConfig.value("Threshold", empty); 83abcc94faSVijay Khemka if (!threshold.empty()) 84abcc94faSVijay Khemka { 85f15189e3SMatt Spinler // Only create the threshold interfaces if 86ce675228SMatt Spinler // at least one of their values is present. 87f15189e3SMatt Spinler 88f15189e3SMatt Spinler if (threshold.contains("CriticalHigh") || 89f15189e3SMatt Spinler threshold.contains("CriticalLow")) 90f15189e3SMatt Spinler { 91fdb826d5SPatrick Williams criticalIface = std::make_unique<Threshold<CriticalObject>>( 92fdb826d5SPatrick Williams bus, objPath.c_str()); 93f15189e3SMatt Spinler 94f15189e3SMatt Spinler criticalIface->criticalHigh(threshold.value( 95f15189e3SMatt Spinler "CriticalHigh", std::numeric_limits<double>::quiet_NaN())); 96f15189e3SMatt Spinler criticalIface->criticalLow(threshold.value( 97f15189e3SMatt Spinler "CriticalLow", std::numeric_limits<double>::quiet_NaN())); 98f15189e3SMatt Spinler } 99f15189e3SMatt Spinler 100f15189e3SMatt Spinler if (threshold.contains("WarningHigh") || 101f15189e3SMatt Spinler threshold.contains("WarningLow")) 102f15189e3SMatt Spinler { 103fdb826d5SPatrick Williams warningIface = std::make_unique<Threshold<WarningObject>>( 104fdb826d5SPatrick Williams bus, objPath.c_str()); 105f15189e3SMatt Spinler 106f15189e3SMatt Spinler warningIface->warningHigh(threshold.value( 107f15189e3SMatt Spinler "WarningHigh", std::numeric_limits<double>::quiet_NaN())); 108f15189e3SMatt Spinler warningIface->warningLow(threshold.value( 109f15189e3SMatt Spinler "WarningLow", std::numeric_limits<double>::quiet_NaN())); 110f15189e3SMatt Spinler } 111f15189e3SMatt Spinler 112ce675228SMatt Spinler if (threshold.contains("HardShutdownHigh") || 113ce675228SMatt Spinler threshold.contains("HardShutdownLow")) 114ce675228SMatt Spinler { 115fdb826d5SPatrick Williams hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>( 116fdb826d5SPatrick Williams bus, objPath.c_str()); 117ce675228SMatt Spinler 118ce675228SMatt Spinler hardShutdownIface->hardShutdownHigh(threshold.value( 119ce675228SMatt Spinler "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN())); 120ce675228SMatt Spinler hardShutdownIface->hardShutdownLow(threshold.value( 121ce675228SMatt Spinler "HardShutdownLow", std::numeric_limits<double>::quiet_NaN())); 122ce675228SMatt Spinler } 123ce675228SMatt Spinler 124ce675228SMatt Spinler if (threshold.contains("SoftShutdownHigh") || 125ce675228SMatt Spinler threshold.contains("SoftShutdownLow")) 126ce675228SMatt Spinler { 127fdb826d5SPatrick Williams softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>( 128fdb826d5SPatrick Williams bus, objPath.c_str()); 129ce675228SMatt Spinler 130ce675228SMatt Spinler softShutdownIface->softShutdownHigh(threshold.value( 131ce675228SMatt Spinler "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN())); 132ce675228SMatt Spinler softShutdownIface->softShutdownLow(threshold.value( 133ce675228SMatt Spinler "SoftShutdownLow", std::numeric_limits<double>::quiet_NaN())); 134ce675228SMatt Spinler } 135b306b03dSMatt Spinler 136b306b03dSMatt Spinler if (threshold.contains("PerformanceLossHigh") || 137b306b03dSMatt Spinler threshold.contains("PerformanceLossLow")) 138b306b03dSMatt Spinler { 139b306b03dSMatt Spinler perfLossIface = std::make_unique<Threshold<PerformanceLossObject>>( 140b306b03dSMatt Spinler bus, objPath.c_str()); 141b306b03dSMatt Spinler 142b306b03dSMatt Spinler perfLossIface->performanceLossHigh( 143b306b03dSMatt Spinler threshold.value("PerformanceLossHigh", 144b306b03dSMatt Spinler std::numeric_limits<double>::quiet_NaN())); 145b306b03dSMatt Spinler perfLossIface->performanceLossLow( 146b306b03dSMatt Spinler threshold.value("PerformanceLossLow", 147b306b03dSMatt Spinler std::numeric_limits<double>::quiet_NaN())); 148b306b03dSMatt Spinler } 149c62a5548SVijay Khemka } 150abcc94faSVijay Khemka 151f6443742SHarvey Wu /* Get MaxValue, MinValue setting if defined in config */ 152f6443742SHarvey Wu auto confDesc = sensorConfig.value("Desc", empty); 153f6443742SHarvey Wu if (auto maxConf = confDesc.find("MaxValue"); 154f6443742SHarvey Wu maxConf != confDesc.end() && maxConf->is_number()) 155f6443742SHarvey Wu { 156f6443742SHarvey Wu ValueIface::maxValue(maxConf->get<double>()); 157f6443742SHarvey Wu } 158f6443742SHarvey Wu if (auto minConf = confDesc.find("MinValue"); 159f6443742SHarvey Wu minConf != confDesc.end() && minConf->is_number()) 160f6443742SHarvey Wu { 161f6443742SHarvey Wu ValueIface::minValue(minConf->get<double>()); 162f6443742SHarvey Wu } 163f6443742SHarvey Wu 164abcc94faSVijay Khemka /* Get expression string */ 165abcc94faSVijay Khemka exprStr = sensorConfig.value("Expression", ""); 166abcc94faSVijay Khemka 167abcc94faSVijay Khemka /* Get all the parameter listed in configuration */ 168abcc94faSVijay Khemka auto params = sensorConfig.value("Params", empty); 169abcc94faSVijay Khemka 170abcc94faSVijay Khemka /* Check for constant parameter */ 171abcc94faSVijay Khemka const auto& consParams = params.value("ConstParam", empty); 172abcc94faSVijay Khemka if (!consParams.empty()) 173abcc94faSVijay Khemka { 174abcc94faSVijay Khemka for (auto& j : consParams) 175abcc94faSVijay Khemka { 176abcc94faSVijay Khemka if (j.find("ParamName") != j.end()) 177abcc94faSVijay Khemka { 178abcc94faSVijay Khemka auto paramPtr = std::make_unique<SensorParam>(j["Value"]); 1793ed9a516SVijay Khemka std::string name = j["ParamName"]; 1803ed9a516SVijay Khemka symbols.create_variable(name); 1813ed9a516SVijay Khemka paramMap.emplace(std::move(name), std::move(paramPtr)); 182abcc94faSVijay Khemka } 183abcc94faSVijay Khemka else 184abcc94faSVijay Khemka { 185abcc94faSVijay Khemka /* Invalid configuration */ 186abcc94faSVijay Khemka throw std::invalid_argument( 187abcc94faSVijay Khemka "ParamName not found in configuration"); 188abcc94faSVijay Khemka } 189abcc94faSVijay Khemka } 190abcc94faSVijay Khemka } 191abcc94faSVijay Khemka 1927452a867SVijay Khemka /* Check for dbus parameter */ 1937452a867SVijay Khemka auto dbusParams = params.value("DbusParam", empty); 1947452a867SVijay Khemka if (!dbusParams.empty()) 1957452a867SVijay Khemka { 1967452a867SVijay Khemka for (auto& j : dbusParams) 1977452a867SVijay Khemka { 1987452a867SVijay Khemka /* Get parameter dbus sensor descriptor */ 1997452a867SVijay Khemka auto desc = j.value("Desc", empty); 2007452a867SVijay Khemka if ((!desc.empty()) && (j.find("ParamName") != j.end())) 2017452a867SVijay Khemka { 2027452a867SVijay Khemka std::string sensorType = desc.value("SensorType", ""); 2037452a867SVijay Khemka std::string name = desc.value("Name", ""); 2047452a867SVijay Khemka 2057452a867SVijay Khemka if (!sensorType.empty() && !name.empty()) 2067452a867SVijay Khemka { 2077452a867SVijay Khemka std::string objPath(sensorDbusPath); 2087452a867SVijay Khemka objPath += sensorType + "/" + name; 2097452a867SVijay Khemka 21051f898e2SVijay Khemka auto paramPtr = 21151f898e2SVijay Khemka std::make_unique<SensorParam>(bus, objPath, this); 2123ed9a516SVijay Khemka std::string name = j["ParamName"]; 2133ed9a516SVijay Khemka symbols.create_variable(name); 2143ed9a516SVijay Khemka paramMap.emplace(std::move(name), std::move(paramPtr)); 2157452a867SVijay Khemka } 2167452a867SVijay Khemka } 2177452a867SVijay Khemka } 2187452a867SVijay Khemka } 219abcc94faSVijay Khemka 2203ed9a516SVijay Khemka symbols.add_constants(); 2219f1ef4f5SMatt Spinler symbols.add_package(vecopsPackage); 2223ed9a516SVijay Khemka expression.register_symbol_table(symbols); 2233ed9a516SVijay Khemka 2243ed9a516SVijay Khemka /* parser from exprtk */ 2253ed9a516SVijay Khemka exprtk::parser<double> parser{}; 226ddc6dcd6SMatt Spinler if (!parser.compile(exprStr, expression)) 227ddc6dcd6SMatt Spinler { 228ddc6dcd6SMatt Spinler log<level::ERR>("Expression compilation failed"); 229ddc6dcd6SMatt Spinler 230ddc6dcd6SMatt Spinler for (std::size_t i = 0; i < parser.error_count(); ++i) 231ddc6dcd6SMatt Spinler { 232ddc6dcd6SMatt Spinler auto error = parser.get_error(i); 233ddc6dcd6SMatt Spinler 234ddc6dcd6SMatt Spinler log<level::ERR>( 235ddc6dcd6SMatt Spinler fmt::format( 236ddc6dcd6SMatt Spinler "Position: {} Type: {} Message: {}", error.token.position, 237ddc6dcd6SMatt Spinler exprtk::parser_error::to_str(error.mode), error.diagnostic) 238ddc6dcd6SMatt Spinler .c_str()); 239ddc6dcd6SMatt Spinler } 240ddc6dcd6SMatt Spinler throw std::runtime_error("Expression compilation failed"); 241ddc6dcd6SMatt Spinler } 2423ed9a516SVijay Khemka 243abcc94faSVijay Khemka /* Print all parameters for debug purpose only */ 244abcc94faSVijay Khemka if (DEBUG) 245abcc94faSVijay Khemka printParams(paramMap); 246abcc94faSVijay Khemka } 247abcc94faSVijay Khemka 248abcc94faSVijay Khemka void VirtualSensor::setSensorValue(double value) 249abcc94faSVijay Khemka { 250*543bf668SPatrick Williams value = std::clamp(value, ValueIface::minValue(), ValueIface::maxValue()); 251abcc94faSVijay Khemka ValueIface::value(value); 252abcc94faSVijay Khemka } 253abcc94faSVijay Khemka 254abcc94faSVijay Khemka void VirtualSensor::updateVirtualSensor() 2553ed9a516SVijay Khemka { 2563ed9a516SVijay Khemka for (auto& param : paramMap) 2573ed9a516SVijay Khemka { 2583ed9a516SVijay Khemka auto& name = param.first; 2593ed9a516SVijay Khemka auto& data = param.second; 2603ed9a516SVijay Khemka if (auto var = symbols.get_variable(name)) 2613ed9a516SVijay Khemka { 2623ed9a516SVijay Khemka var->ref() = data->getParamValue(); 2633ed9a516SVijay Khemka } 2643ed9a516SVijay Khemka else 2653ed9a516SVijay Khemka { 2663ed9a516SVijay Khemka /* Invalid parameter */ 2673ed9a516SVijay Khemka throw std::invalid_argument("ParamName not found in symbols"); 2683ed9a516SVijay Khemka } 2693ed9a516SVijay Khemka } 2703ed9a516SVijay Khemka double val = expression.value(); 27132a7156bSVijay Khemka 27232a7156bSVijay Khemka /* Set sensor value to dbus interface */ 2733ed9a516SVijay Khemka setSensorValue(val); 27432a7156bSVijay Khemka 2753ed9a516SVijay Khemka if (DEBUG) 2763ed9a516SVijay Khemka std::cout << "Sensor value is " << val << "\n"; 27732a7156bSVijay Khemka 2788f5e6119SMatt Spinler /* Check sensor thresholds and log required message */ 279b306b03dSMatt Spinler checkThresholds(val, perfLossIface); 280fdb826d5SPatrick Williams checkThresholds(val, warningIface); 281fdb826d5SPatrick Williams checkThresholds(val, criticalIface); 282fdb826d5SPatrick Williams checkThresholds(val, softShutdownIface); 283fdb826d5SPatrick Williams checkThresholds(val, hardShutdownIface); 2843ed9a516SVijay Khemka } 285abcc94faSVijay Khemka 286abcc94faSVijay Khemka /** @brief Parsing Virtual Sensor config JSON file */ 287abcc94faSVijay Khemka Json VirtualSensors::parseConfigFile(const std::string configFile) 288abcc94faSVijay Khemka { 289abcc94faSVijay Khemka std::ifstream jsonFile(configFile); 290abcc94faSVijay Khemka if (!jsonFile.is_open()) 291abcc94faSVijay Khemka { 292abcc94faSVijay Khemka log<level::ERR>("config JSON file not found", 293abcc94faSVijay Khemka entry("FILENAME = %s", configFile.c_str())); 294abcc94faSVijay Khemka throw std::exception{}; 295abcc94faSVijay Khemka } 296abcc94faSVijay Khemka 297abcc94faSVijay Khemka auto data = Json::parse(jsonFile, nullptr, false); 298abcc94faSVijay Khemka if (data.is_discarded()) 299abcc94faSVijay Khemka { 300abcc94faSVijay Khemka log<level::ERR>("config readings JSON parser failure", 301abcc94faSVijay Khemka entry("FILENAME = %s", configFile.c_str())); 302abcc94faSVijay Khemka throw std::exception{}; 303abcc94faSVijay Khemka } 304abcc94faSVijay Khemka 305abcc94faSVijay Khemka return data; 306abcc94faSVijay Khemka } 307abcc94faSVijay Khemka 308e0d371e4SVijay Khemka std::map<std::string, ValueIface::Unit> unitMap = { 309e0d371e4SVijay Khemka {"temperature", ValueIface::Unit::DegreesC}, 310e0d371e4SVijay Khemka {"fan_tach", ValueIface::Unit::RPMS}, 311e0d371e4SVijay Khemka {"voltage", ValueIface::Unit::Volts}, 312e0d371e4SVijay Khemka {"altitude", ValueIface::Unit::Meters}, 313e0d371e4SVijay Khemka {"current", ValueIface::Unit::Amperes}, 314e0d371e4SVijay Khemka {"power", ValueIface::Unit::Watts}, 315e0d371e4SVijay Khemka {"energy", ValueIface::Unit::Joules}, 3162b56ddb3SKumar Thangavel {"utilization", ValueIface::Unit::Percent}, 3172b56ddb3SKumar Thangavel {"airflow", ValueIface::Unit::CFM}}; 318e0d371e4SVijay Khemka 319abcc94faSVijay Khemka void VirtualSensors::createVirtualSensors() 320abcc94faSVijay Khemka { 321abcc94faSVijay Khemka static const Json empty{}; 322abcc94faSVijay Khemka 323abcc94faSVijay Khemka auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE); 324abcc94faSVijay Khemka // print values 325abcc94faSVijay Khemka if (DEBUG) 326abcc94faSVijay Khemka std::cout << "Config json data:\n" << data << "\n\n"; 327abcc94faSVijay Khemka 328abcc94faSVijay Khemka /* Get virtual sensors config data */ 329abcc94faSVijay Khemka for (const auto& j : data) 330abcc94faSVijay Khemka { 331abcc94faSVijay Khemka auto desc = j.value("Desc", empty); 332abcc94faSVijay Khemka if (!desc.empty()) 333abcc94faSVijay Khemka { 334abcc94faSVijay Khemka std::string sensorType = desc.value("SensorType", ""); 335abcc94faSVijay Khemka std::string name = desc.value("Name", ""); 336abcc94faSVijay Khemka 337abcc94faSVijay Khemka if (!name.empty() && !sensorType.empty()) 338abcc94faSVijay Khemka { 339e0d371e4SVijay Khemka if (unitMap.find(sensorType) == unitMap.end()) 340e0d371e4SVijay Khemka { 341e0d371e4SVijay Khemka log<level::ERR>("Sensor type is not supported", 342e0d371e4SVijay Khemka entry("TYPE = %s", sensorType.c_str())); 343e0d371e4SVijay Khemka } 344e0d371e4SVijay Khemka else 345e0d371e4SVijay Khemka { 346abcc94faSVijay Khemka std::string objPath(sensorDbusPath); 347abcc94faSVijay Khemka objPath += sensorType + "/" + name; 348abcc94faSVijay Khemka 34932a7156bSVijay Khemka auto virtualSensorPtr = std::make_unique<VirtualSensor>( 35032a7156bSVijay Khemka bus, objPath.c_str(), j, name); 351abcc94faSVijay Khemka 352abcc94faSVijay Khemka log<level::INFO>("Added a new virtual sensor", 353abcc94faSVijay Khemka entry("NAME = %s", name.c_str())); 3543ed9a516SVijay Khemka virtualSensorPtr->updateVirtualSensor(); 355e0d371e4SVijay Khemka 356e0d371e4SVijay Khemka /* Initialize unit value for virtual sensor */ 357e0d371e4SVijay Khemka virtualSensorPtr->ValueIface::unit(unitMap[sensorType]); 358e0d371e4SVijay Khemka 3593ed9a516SVijay Khemka virtualSensorsMap.emplace(std::move(name), 3603ed9a516SVijay Khemka std::move(virtualSensorPtr)); 361abcc94faSVijay Khemka } 362e0d371e4SVijay Khemka } 363abcc94faSVijay Khemka else 364abcc94faSVijay Khemka { 365abcc94faSVijay Khemka log<level::ERR>("Sensor type or name not found in config file"); 366abcc94faSVijay Khemka } 367abcc94faSVijay Khemka } 368abcc94faSVijay Khemka else 369abcc94faSVijay Khemka { 370abcc94faSVijay Khemka log<level::ERR>( 371abcc94faSVijay Khemka "Descriptor for new virtual sensor not found in config file"); 372abcc94faSVijay Khemka } 373abcc94faSVijay Khemka } 374abcc94faSVijay Khemka } 375abcc94faSVijay Khemka 376abcc94faSVijay Khemka } // namespace virtualSensor 377abcc94faSVijay Khemka } // namespace phosphor 378abcc94faSVijay Khemka 379abcc94faSVijay Khemka /** 380abcc94faSVijay Khemka * @brief Main 381abcc94faSVijay Khemka */ 382abcc94faSVijay Khemka int main() 383abcc94faSVijay Khemka { 384abcc94faSVijay Khemka 385abcc94faSVijay Khemka // Get a default event loop 386abcc94faSVijay Khemka auto event = sdeventplus::Event::get_default(); 387abcc94faSVijay Khemka 388abcc94faSVijay Khemka // Get a handle to system dbus 389abcc94faSVijay Khemka auto bus = sdbusplus::bus::new_default(); 390abcc94faSVijay Khemka 3916c19e7d2SMatt Spinler // Add the ObjectManager interface 3926c19e7d2SMatt Spinler sdbusplus::server::manager::manager objManager(bus, "/"); 3936c19e7d2SMatt Spinler 394abcc94faSVijay Khemka // Create an virtual sensors object 395abcc94faSVijay Khemka phosphor::virtualSensor::VirtualSensors virtualSensors(bus); 396abcc94faSVijay Khemka 397abcc94faSVijay Khemka // Request service bus name 398abcc94faSVijay Khemka bus.request_name(busName); 399abcc94faSVijay Khemka 400abcc94faSVijay Khemka // Attach the bus to sd_event to service user requests 401abcc94faSVijay Khemka bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL); 402abcc94faSVijay Khemka event.loop(); 403abcc94faSVijay Khemka 404abcc94faSVijay Khemka return 0; 405abcc94faSVijay Khemka } 406