/** * @file XNEngine.cpp * @author jinchao * @brief 引擎类 * @version 1.0 * @date 2025-02-14 * * @copyright Copyright (c) 2025 COMAC * */ #include "XNEngine.h" #include "../XNCore/XNTimeManager.h" #include "../XNCore/XNThreadManager.h" #include "../XNCore/XNDDSManager.h" #include "../XNCore/XNEventManager.h" #include "../XNCore/XNServiceManager.h" #include "../XNCore/XNModelManager.h" #include "../XNCore/XNScenarioManager.h" // 引擎类构造函数 XNEngine::XNEngine() { // 创建框架对象 framework = std::make_shared(); // 引擎状态写入器 engineStatusWriter = nullptr; // 测试模式 isTestMode = false; // 初始化类型 initializeType = 0; } // 引擎类析构函数 XNEngine::~XNEngine() { } // 仿真控制监听器 void XNEngine::SimControlListener(const XNSim::XNSimControl::XNRuntimeControl &cmd) { if (!framework) { return; } if (cmd.XNSimCmd() == 1) { // 如果命令是暂停 framework->SimControl(0, SimControlCmd::Suspend); } else if (cmd.XNSimCmd() == 2) { // 如果命令是继续 framework->SimControl(0, SimControlCmd::Continue); } else if (cmd.XNSimCmd() == 3) { // 如果命令是终止 framework->SimControl(0, SimControlCmd::Abort); //TODO 后续收到结束指令后再结束,还需要最后发一次终止状态 engineRunning = false; } } // 设置日志级别 bool XNEngine::SetLogLevel(const std::string &XmlPath) { // 打开配置文件 std::ifstream file(XmlPath); if (!file.is_open()) { std::cerr << "0x1003 Failed to open the runtime environment configuration file, " "the engine will exit!" << std::endl; return false; } // 解析配置文件 tinyxml2::XMLDocument doc; if (doc.LoadFile(XmlPath.c_str()) != tinyxml2::XML_SUCCESS) { std::cerr << "0x1004 Failed to parse the runtime environment configuration file, " "the engine will exit!" << std::endl; return false; } // 获取根元素 tinyxml2::XMLElement *root = doc.FirstChildElement("Scenario"); if (!root) { std::cerr << "0x1005 Failed to find Scenario element in configuration file!" << std::endl; return false; } // 顺便读取一下CPU亲和性 int cpus = sysconf(_SC_NPROCESSORS_ONLN); std::cout << "Current number of CPU cores-> " << cpus << std::endl; // 设置CPU亲和性 cpu_set_t mask; CPU_ZERO(&mask); CPUAffinity = 0; //获取CPU亲和性配置 tinyxml2::XMLElement *envNode = root->FirstChildElement("Environment"); if (envNode) { const char *cpuAffinityStr = envNode->Attribute("CPUAffinity"); if (cpuAffinityStr) { std::string affinityStr(cpuAffinityStr); std::istringstream iss(affinityStr); std::string cpuIndex; while (std::getline(iss, cpuIndex, ',')) { try { int index = std::stoi(cpuIndex); if (index >= 0 && index < cpus) { CPUAffinity |= (1 << index); CPU_SET(index, &mask); } } catch (const std::exception &e) { std::cerr << "Invalid CPU affinity value: " << cpuIndex << std::endl; } } } } if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { std::cerr << "0x1020 Failed to set engine CPU affinity-> " << strerror(errno) << std::endl; return false; } std::cout << "Successfully set engine CPU affinity-> " << CPUAffinity << std::endl; // 锁定内存 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { std::cerr << "0x1021 Failed to lock engine memory-> " << strerror(errno) << std::endl; return false; } std::cout << "Successfully locked engine memory!" << std::endl; // 获取配置文件中的控制台输出元素 tinyxml2::XMLElement *consoleOutputNode = root->FirstChildElement("ConsoleOutput"); if (!consoleOutputNode) { std::cout << "The runtime environment configuration file does not contain " "the ConsoleOutput element, the Console will Output all Log!" << std::endl; } else { // 获取配置文件中的调试日志输出元素 const char *debugConsoleOutput = consoleOutputNode->Attribute("Debug"); if (debugConsoleOutput && (strcmp(debugConsoleOutput, "true") == 0 || strcmp(debugConsoleOutput, "1") == 0 || strcmp(debugConsoleOutput, "True") == 0 || strcmp(debugConsoleOutput, "TRUE") == 0)) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, false); } // 获取配置文件中的信息日志输出元素 const char *infoConsoleOutput = consoleOutputNode->Attribute("Info"); if (infoConsoleOutput && (strcmp(infoConsoleOutput, "true") == 0 || strcmp(infoConsoleOutput, "1") == 0 || strcmp(infoConsoleOutput, "True") == 0 || strcmp(infoConsoleOutput, "TRUE") == 0)) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, false); } // 获取配置文件中的警告日志输出元素 const char *warningConsoleOutput = consoleOutputNode->Attribute("Warning"); if (warningConsoleOutput && (strcmp(warningConsoleOutput, "true") == 0 || strcmp(warningConsoleOutput, "1") == 0 || strcmp(warningConsoleOutput, "True") == 0 || strcmp(warningConsoleOutput, "TRUE") == 0)) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, false); } // 获取配置文件中的错误日志输出元素 const char *errorConsoleOutput = consoleOutputNode->Attribute("Error"); if (errorConsoleOutput && (strcmp(errorConsoleOutput, "true") == 0 || strcmp(errorConsoleOutput, "1") == 0 || strcmp(errorConsoleOutput, "True") == 0 || strcmp(errorConsoleOutput, "TRUE") == 0)) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, false); } } // 获取配置文件中的日志元素 tinyxml2::XMLElement *logNode = root->FirstChildElement("Log"); if (!logNode) { std::cout << "The runtime environment configuration file does not contain " "the Log element, the Log File will record all Log!" << std::endl; } else { // 获取配置文件中的调试日志输出元素 const char *debugLog = logNode->Attribute("Debug"); if (debugLog && (strcmp(debugLog, "true") == 0 || strcmp(debugLog, "1") == 0 || strcmp(debugLog, "True") == 0 || strcmp(debugLog, "TRUE") == 0)) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, false); } // 获取配置文件中的信息日志输出元素 const char *infoLog = logNode->Attribute("Info"); if (infoLog && (strcmp(infoLog, "true") == 0 || strcmp(infoLog, "1") == 0 || strcmp(infoLog, "True") == 0 || strcmp(infoLog, "TRUE") == 0)) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, false); } // 获取配置文件中的警告日志输出元素 const char *warningLog = logNode->Attribute("Warning"); if (warningLog && (strcmp(warningLog, "true") == 0 || strcmp(warningLog, "1") == 0 || strcmp(warningLog, "True") == 0 || strcmp(warningLog, "TRUE") == 0)) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, false); } // 获取配置文件中的错误日志输出元素 const char *errorLog = logNode->Attribute("Error"); if (errorLog && (strcmp(errorLog, "true") == 0 || strcmp(errorLog, "1") == 0 || strcmp(errorLog, "True") == 0 || strcmp(errorLog, "TRUE") == 0)) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, false); } } // 关闭配置文件 file.close(); // 返回成功 return true; } // 发布引擎状态 void XNEngine::PublishEngineStatus() { if (!framework) { return; } // 如果引擎状态写入器存在 if (engineStatusWriter) { // 创建引擎状态对象 XNSim::XNSimStatus::XNEngineStatus engineStatus; // 创建内核状态对象 XNSim::XNSimStatus::XNCoreStatus coreStatus; // 设置引擎名称 engineStatus.XNEngineName("XNEngine"); // 设置引擎ID engineStatus.XNEngineID(getpid()); // 设置引擎亲和性 engineStatus.XNEngineAff(CPUAffinity); // 获取时间管理器 XNTimeManagerPtr timeManager = framework->GetTimeManager(); // 如果时间管理器存在 if (timeManager) { // 设置引擎状态 engineStatus.XNEngineSt((uint32_t)timeManager->GetStatus()); // 设置内核状态 coreStatus.XNTMStatus((uint32_t)timeManager->GetFrameObjectStatus()); } else { // 设置引擎状态 engineStatus.XNEngineSt(4); // 设置内核状态 coreStatus.XNTMStatus(2); } // 获取线程管理器 XNThreadManagerPtr threadManager = framework->GetThreadManager(); // 如果线程管理器存在 if (threadManager) { // 设置内核状态 coreStatus.XNThMStatus((uint32_t)threadManager->GetFrameObjectStatus()); // 设置引擎状态 engineStatus.XNThCnt(threadManager->GetThreadCount()); } else { // 设置内核状态 coreStatus.XNThMStatus(2); } // 获取DDS管理器 XNDDSManagerPtr ddsManager = framework->GetDDSManager(); // 如果DDS管理器存在 if (ddsManager) { // 设置内核状态 coreStatus.XNDMStatus((uint32_t)ddsManager->GetFrameObjectStatus()); } else { // 设置内核状态 coreStatus.XNDMStatus(2); } // 获取事件管理器 XNEventManagerPtr eventManager = framework->GetEventManager(); // 如果事件管理器存在 if (eventManager) { // 设置内核状态 coreStatus.XNEMStatus((uint32_t)eventManager->GetFrameObjectStatus()); } else { // 设置内核状态 coreStatus.XNEMStatus(2); } // 获取服务管理器 XNServiceManagerPtr serviceManager = framework->GetServiceManager(); // 如果服务管理器存在 if (serviceManager) { // 设置内核状态 coreStatus.XNSMStatus((uint32_t)serviceManager->GetFrameObjectStatus()); } else { // 设置内核状态 coreStatus.XNSMStatus(2); } // 获取模型管理器 XNModelManagerPtr modelManager = framework->GetModelManager(); // 如果模型管理器存在 if (modelManager) { // 设置内核状态 coreStatus.XNMMStatus((uint32_t)modelManager->GetFrameObjectStatus()); } else { // 设置内核状态 coreStatus.XNMMStatus(2); } // 获取场景管理器 XNScenarioManagerPtr scenarioManager = framework->GetScenarioManager(); // 如果场景管理器存在 if (scenarioManager) { // 设置内核状态 coreStatus.XNSDStatus((uint32_t)scenarioManager->GetFrameObjectStatus()); } else { // 设置内核状态 coreStatus.XNSDStatus(2); } // 设置框架状态 coreStatus.XNFWStatus((uint32_t)frameworkStatus); // 设置引擎状态 engineStatus.XNCoreSt(coreStatus); // 写入引擎状态 engineStatusWriter->write(&engineStatus); // 记录调试日志 LOG_DEBUG("XNEngine Write DDS!"); } } // 运行引擎 bool XNEngine::Run(const std::string &XmlPath) { if (!framework) { return false; } // 设置日志级别 bool isReady = SetLogLevel(XmlPath); // 如果设置日志级别失败 if (!isReady) { // 返回失败 return false; } // 设置场景XML路径 framework->SetScenarioXml(XmlPath); // 设置CPU亲和性 framework->SetCpuAffinity(CPUAffinity); // 单次触发初始化信号 bool ret = framework->Initialize(0); // 如果初始化失败 if (!ret) { // 返回失败 return false; } // 如果初始化成功 // 设置框架状态 frameworkStatus = XNFrameObjectStatus::Initialized; // 记录信息日志 LOG_INFO("XNEngine Initialize Success!"); // 如果测试模式 if (isTestMode) { // 记录信息日志 LOG_INFO("Verification passed!"); // 返回成功 return true; } ret = framework->PrepareForExecute(); // 如果准备执行失败 if (!ret) { // 返回失败 return false; } // 设置框架状态 frameworkStatus = XNFrameObjectStatus::Ready; // 获取DDS管理器 XNDDSManagerPtr ddsManager = framework->GetDDSManager(); // 如果DDS管理器存在 if (ddsManager) { // 注册仿真控制订阅者 auto func = std::bind(&XNEngine::SimControlListener, this, std::placeholders::_1); ddsManager->RegisterSubscriber( "XNSim::XNSimControl::XNRuntimeControl", 0, func); // 触发仿真控制信号 framework->SimControl(0, SimControlCmd::Start); // 注册引擎状态发布者 engineStatusWriter = ddsManager->RegisterPublisher( "XNSim::XNSimStatus::XNEngineStatus", 0); // 如果引擎状态写入器存在 if (engineStatusWriter) { // 设置引擎运行标志 engineRunning = true; while (engineRunning) { // 发布一次初始状态 PublishEngineStatus(); // 等待1秒 std::this_thread::sleep_for(std::chrono::seconds(1)); } if (!engineRunning) { // 取消注册引擎状态发布者 //ddsManager->UnregisterPublisher("XNSim::XNSimStatus::XNEngineStatus"); //ddsManager->UnregisterSubscriber("XNSim::XNSimControl::XNRuntimeControl"); } } } else { // 记录错误日志 LOG_ERROR("0x1007 Failed to prepare for execution, the engine will exit!"); } // 返回成功 return true; } bool XNEngine::Run(const uint32_t &ConfigId) { return true; } // 设置测试模式 void XNEngine::SetTestMode(bool isTestMode) { // 设置测试模式 this->isTestMode = isTestMode; }