/** * @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" #include // 引擎类构造函数 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::ParseConfig(const std::string &XmlPath) { size_t index = XmlPath.find_last_of('.'); if (index != std::string::npos) { std::string suffix = XmlPath.substr(index); if (suffix != ".xml" && suffix != ".sce") { std::cerr << "0x1005 配置文件不是 .xml 或 .sce 文件, 引擎将退出!" << std::endl; return false; } } else { std::cerr << "0x1006 配置文件没有 .xml 或 .sce 的后缀名, 引擎将退出!" << std::endl; return false; } // 打开配置文件 std::ifstream file(XmlPath); if (!file.is_open()) { std::cerr << "0x1007 打开配置文件失败, 引擎将退出!" << std::endl; return false; } // 解析配置文件 tinyxml2::XMLDocument doc; if (doc.LoadFile(XmlPath.c_str()) != tinyxml2::XML_SUCCESS) { std::cerr << "0x1008 解析配置文件失败, 引擎将退出!" << std::endl; return false; } // 获取根元素 tinyxml2::XMLElement *root = doc.FirstChildElement("Scenario"); if (!root) { std::cerr << "0x1009 配置文件中未找到 Scenario 根元素, 引擎将退出!" << std::endl; return false; } // 顺便读取一下CPU亲和性 int cpus = sysconf(_SC_NPROCESSORS_ONLN); std::cout << "当前CPU核心数-> " << 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 << "0x1010 无效的CPU亲和性值: " << cpuIndex << std::endl; } } } } if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { std::cerr << "0x1011 设置引擎CPU亲和性失败-> " << strerror(errno) << std::endl; return false; } std::cout << "成功设置引擎CPU亲和性-> " << CPUAffinity << std::endl; // 锁定内存 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { std::cerr << "0x1012 锁定引擎内存失败-> " << strerror(errno) << std::endl; return false; } std::cout << "成功锁定引擎内存!" << std::endl; // 获取配置文件中的日志元素 bool isDebug = false; bool isInfo = false; bool isWarn = false; bool isError = false; // 获取配置文件中的控制台输出元素 tinyxml2::XMLElement *consoleOutputNode = root->FirstChildElement("ConsoleOutput"); if (!consoleOutputNode) { std::cout << "0x1013 配置文件中未找到 ConsoleOutput 元素, 控制台将输出所有日志!" << 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)) { isDebug = true; } else { isDebug = 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)) { isInfo = true; } else { isInfo = 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)) { isWarn = true; } else { isWarn = 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)) { isError = true; } else { isError = false; } } // 设置控制台输出 SetConsoleOutput(isDebug, isInfo, isWarn, isError); tinyxml2::XMLElement *logNode = root->FirstChildElement("Log"); if (!logNode) { std::cout << "0x1014 配置文件中未找到 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)) { isDebug = true; } else { isDebug = 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)) { isInfo = true; } else { isInfo = 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)) { isWarn = true; } else { isWarn = 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)) { isError = true; } else { isError = false; } } // 设置日志级别 SetLogLevel(isDebug, isInfo, isWarn, isError); // 关闭配置文件 file.close(); // 返回成功 return true; } // 设置控制台输出 bool XNEngine::SetConsoleOutput(bool isDebug, bool isInfo, bool isWarn, bool isError) { if (isDebug) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, false); } if (isInfo) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, false); } if (isWarn) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, false); } if (isError) { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, true); } else { XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, false); } return true; } // 设置日志级别 bool XNEngine::SetLogLevel(bool isDebug, bool isInfo, bool isWarn, bool isError) { if (isDebug) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, false); } if (isInfo) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, false); } if (isWarn) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, false); } if (isError) { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, true); } else { XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, false); } 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("引擎运行状态 DDS 写入成功!"); } } // 运行引擎 bool XNEngine::Run(const std::string &XmlPath, const uint32_t InitializeType) { if (!framework) { return false; } if (InitializeType == 0) { // 解析配置文件 bool isReady = ParseConfig(XmlPath); // 如果解析配置文件失败 if (!isReady) { // 返回失败 return false; } } else if (InitializeType == 1) { // 解析数据库 bool isReady = ParseDataBase(XmlPath); // 如果解析数据库失败 if (!isReady) { // 返回失败 return false; } } // 设置场景XML路径 framework->SetScenarioXml(XmlPath); // 设置CPU亲和性 framework->SetCpuAffinity(CPUAffinity); // 单次触发初始化信号 bool ret = framework->Initialize(InitializeType); // 如果初始化失败 if (!ret) { LOG_ERROR("0x1012 初始化失败, 引擎将退出!"); // 返回失败 return false; } // 如果初始化成功 // 设置框架状态 frameworkStatus = XNFrameObjectStatus::Initialized; // 记录信息日志 LOG_INFO("引擎初始化成功!"); // 如果测试模式 if (isTestMode) { // 记录信息日志 LOG_INFO("引擎测试通过!"); // 返回成功 return true; } ret = framework->PrepareForExecute(); // 如果准备执行失败 if (!ret) { LOG_ERROR("0x1013 准备执行失败, 引擎将退出!"); // 返回失败 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("0x1014 无法发送引擎运行状态, 引擎将退出!"); } // 返回成功 return true; } // 运行引擎 bool XNEngine::ParseDataBase(const std::string &ConfigId) { // 获取数据库路径 std::string dbPath = std::getenv("XNCore"); if (dbPath.empty()) { LOG_ERROR("0x1015 未设置XNCore环境变量, 引擎将退出!"); return false; } dbPath += "/database/XNSim.db"; // 打开数据库 sqlite3 *db; if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) { LOG_ERROR("0x1016 打开数据库失败: %1", sqlite3_errmsg(db)); return false; } // 准备SQL语句 std::string sql = "SELECT * FROM Configuration WHERE ConfID = ?"; sqlite3_stmt *stmt; if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { LOG_ERROR("0x1017 准备SQL语句失败: %1", sqlite3_errmsg(db)); sqlite3_close(db); return false; } // 绑定参数 int configIdInt = std::stoi(ConfigId); if (sqlite3_bind_int(stmt, 1, configIdInt) != SQLITE_OK) { LOG_ERROR("0x1018 绑定参数失败: %1", sqlite3_errmsg(db)); sqlite3_finalize(stmt); sqlite3_close(db); return false; } // 执行查询 if (sqlite3_step(stmt) != SQLITE_ROW) { LOG_ERROR("0x1019 未找到配置ID为%1的记录", ConfigId); sqlite3_finalize(stmt); sqlite3_close(db); return false; } int cpus = sysconf(_SC_NPROCESSORS_ONLN); std::cout << "当前CPU核心数-> " << cpus << std::endl; // 设置CPU亲和性 cpu_set_t mask; CPU_ZERO(&mask); CPUAffinity = 0; // 读取配置信息 std::string CPUAff = XNSim::getStringFromSqlite3(stmt, 6); //std::string CPUAff = reinterpret_cast(sqlite3_column_text(stmt, 6)); std::istringstream iss(CPUAff); 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 << "0x1010 无效的CPU亲和性值: " << cpuIndex << std::endl; } } if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { std::cerr << "0x1011 设置引擎CPU亲和性失败-> " << strerror(errno) << std::endl; return false; } std::cout << "成功设置引擎CPU亲和性-> " << CPUAffinity << std::endl; // 锁定内存 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { std::cerr << "0x1012 锁定引擎内存失败-> " << strerror(errno) << std::endl; return false; } std::cout << "成功锁定引擎内存!" << std::endl; auto readBoolean = [](sqlite3_stmt *stmt, int column) -> bool { return sqlite3_column_int(stmt, column) != 0; }; bool isDebug = readBoolean(stmt, 11); bool isInfo = readBoolean(stmt, 12); bool isWarn = readBoolean(stmt, 13); bool isError = readBoolean(stmt, 14); SetConsoleOutput(isDebug, isInfo, isWarn, isError); isDebug = readBoolean(stmt, 15); isInfo = readBoolean(stmt, 16); isWarn = readBoolean(stmt, 17); isError = readBoolean(stmt, 18); SetLogLevel(isDebug, isInfo, isWarn, isError); // 清理资源 sqlite3_finalize(stmt); sqlite3_close(db); return true; } // 设置测试模式 void XNEngine::SetTestMode(bool isTestMode) { // 设置测试模式 this->isTestMode = isTestMode; }