diff --git a/Release/Models/XNATA04DataProcessor.mcfg b/Release/Models/XNATA04DataProcessor_V1.0.0.0.mcfg similarity index 100% rename from Release/Models/XNATA04DataProcessor.mcfg rename to Release/Models/XNATA04DataProcessor_V1.0.0.0.mcfg diff --git a/Release/Models/XNAerodynamics.mcfg b/Release/Models/XNAerodynamics_V1.0.0.0.mcfg similarity index 100% rename from Release/Models/XNAerodynamics.mcfg rename to Release/Models/XNAerodynamics_V1.0.0.0.mcfg diff --git a/Release/Models/XNGroundHandling.mcfg b/Release/Models/XNGroundHandling_V1.0.0.0.mcfg similarity index 100% rename from Release/Models/XNGroundHandling.mcfg rename to Release/Models/XNGroundHandling_V1.0.0.0.mcfg diff --git a/Release/Models/XNWeightBalance.mcfg b/Release/Models/XNWeightBalance_V1.0.0.0.mcfg similarity index 100% rename from Release/Models/XNWeightBalance.mcfg rename to Release/Models/XNWeightBalance_V1.0.0.0.mcfg diff --git a/Release/Models/libXNATA04DataProcessor.so.1.0.0.0 b/Release/Models/libXNATA04DataProcessor.so.1.0.0.0 new file mode 100644 index 0000000..b867af2 Binary files /dev/null and b/Release/Models/libXNATA04DataProcessor.so.1.0.0.0 differ diff --git a/Release/Models/libXNAerodynamics.so.1.0.0.0 b/Release/Models/libXNAerodynamics.so.1.0.0.0 new file mode 100644 index 0000000..6fd7fb0 Binary files /dev/null and b/Release/Models/libXNAerodynamics.so.1.0.0.0 differ diff --git a/Release/Models/libXNGroundHandling.so.1.0.0.0 b/Release/Models/libXNGroundHandling.so.1.0.0.0 new file mode 100644 index 0000000..26cf2bd Binary files /dev/null and b/Release/Models/libXNGroundHandling.so.1.0.0.0 differ diff --git a/Release/Models/libXNWeightBalance.so.1.0.0.0 b/Release/Models/libXNWeightBalance.so.1.0.0.0 new file mode 100644 index 0000000..21b7865 Binary files /dev/null and b/Release/Models/libXNWeightBalance.so.1.0.0.0 differ diff --git a/Release/Scenario/OnlyFlightModel.xml b/Release/Scenario/OnlyFlightModel.xml index 5169e2b..e632118 100755 --- a/Release/Scenario/OnlyFlightModel.xml +++ b/Release/Scenario/OnlyFlightModel.xml @@ -1,15 +1,15 @@ - + - - - - + + + + - + diff --git a/Release/Services/XNUDPService_V1.0.0.0.mcfg b/Release/Services/XNUDPService_V1.0.0.0.mcfg new file mode 100644 index 0000000..8fa1279 --- /dev/null +++ b/Release/Services/XNUDPService_V1.0.0.0.mcfg @@ -0,0 +1,17 @@ + + + XNUDPService + UDP通信服务 + Jin + 1.0.0 + 2025-02-04 10:00:00 + 2025-02-04 10:00:00 + + + + + 12345 + 127.0.0.1 + 54321 + + diff --git a/Release/Services/libXNUDPService.so.1.0.0.0 b/Release/Services/libXNUDPService.so.1.0.0.0 new file mode 100644 index 0000000..c126e07 Binary files /dev/null and b/Release/Services/libXNUDPService.so.1.0.0.0 differ diff --git a/Release/XNEngine b/Release/XNEngine index a5aef0e..c35cdc6 100755 Binary files a/Release/XNEngine and b/Release/XNEngine differ diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 9440b07..f160d20 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/Release/include/XNCore/XNCore_global.h b/Release/include/XNCore/XNCore_global.h index b4ce4bb..e2cae8a 100644 --- a/Release/include/XNCore/XNCore_global.h +++ b/Release/include/XNCore/XNCore_global.h @@ -40,6 +40,8 @@ # include # include # include +# include +# include #endif #include @@ -53,6 +55,8 @@ #include #define FAST_DDS_MACRO eprosima::fastdds::dds +using XN_JSON = nlohmann::json; + /** * @brief 默认基频定义,单位 Hz */ @@ -91,13 +95,6 @@ struct PERIOD_INFO { */ using XNTimePoint = std::chrono::system_clock::time_point; -/** - * @brief 将ISO格式的时间字符串转换为系统时间点 - * @param timeStr ISO格式的时间字符串 (YYYY-MM-DDTHH:mm:ss) - * @return 系统时间点 - */ -extern "C" XNTimePoint XNCORE_EXPORT parseISOTime(const std::string &timeStr); - /** * @brief 系统运行状态枚举类 */ @@ -258,3 +255,37 @@ public: public: \ using ThisType = cls; \ using SuperType = sup; + +#define XN_UNUSED(x) (void)x + +namespace XNSim +{ +template +constexpr typename std::underlying_type::type enumValue(T e) +{ + return static_cast::type>(e); +} + +/** + * @brief 将ISO格式的时间字符串转换为系统时间点 + * @param timeStr ISO格式的时间字符串 (YYYY-MM-DDTHH:mm:ss) + * @return 系统时间点 + */ +extern "C" XNTimePoint XNCORE_EXPORT parseISOTime(const std::string &timeStr); + +extern "C" std::vector XNCORE_EXPORT split(const std::string &str, + const std::string &delim); + +extern "C" std::string XNCORE_EXPORT getFileNameWithoutExt(const std::string &path); + +extern "C" int XNCORE_EXPORT safe_stoi(const std::string &str, int defaultValue = 0); + +inline std::string getStringFromSqlite3(sqlite3_stmt *stmt, int column) +{ + const char *text = reinterpret_cast(sqlite3_column_text(stmt, column)); + if (text == nullptr) { + return ""; + } + return std::string(text); +} +} // namespace XNSim diff --git a/Release/include/XNCore/XNFramework_p.h b/Release/include/XNCore/XNFramework_p.h index cb27a74..2d648c4 100644 --- a/Release/include/XNCore/XNFramework_p.h +++ b/Release/include/XNCore/XNFramework_p.h @@ -77,4 +77,9 @@ struct XNFrameworkPrivate : public XNObjectPrivate { * @brief 场景XML */ std::string scenarioXml; + + /** + * @brief 构型ID + */ + uint32_t configId; }; diff --git a/Release/include/XNCore/XNModelManager.h b/Release/include/XNCore/XNModelManager.h index 4c030b6..b1c6a67 100644 --- a/Release/include/XNCore/XNModelManager.h +++ b/Release/include/XNCore/XNModelManager.h @@ -61,10 +61,14 @@ public: * @brief 加载模型 * @param modelPath: QString类型,模型动态链接库路径 * @param className: QString类型,模型类名 + * @param modelVersion: QString类型,模型版本号 + * @param initialType: UINT32类型,初始化类型 + * @param threadID: UINT32类型,线程ID * @details 加载模型 */ - void LoadModel(const std::string &modelPath, const std::string &className, uint32_t initialType, - uint32_t threadID); + void LoadModel(const std::string &modelPath, const std::string &className, + const std::string &modelVersion, const std::string &planeName, + uint32_t initialType, uint32_t threadID); /** * @brief 注册模型信息 diff --git a/Release/include/XNCore/XNModelObject.h b/Release/include/XNCore/XNModelObject.h index 540781a..2f7153f 100644 --- a/Release/include/XNCore/XNModelObject.h +++ b/Release/include/XNCore/XNModelObject.h @@ -238,6 +238,10 @@ public: public: virtual void RegisterDDSParticipant(); + +private: + void ParseXml(); + void ParseConfig(); }; #define XN_MODEL_INITIALIZE(ClassName) \ diff --git a/Release/include/XNCore/XNScenarioManager.h b/Release/include/XNCore/XNScenarioManager.h index 89a293b..b659e78 100644 --- a/Release/include/XNCore/XNScenarioManager.h +++ b/Release/include/XNCore/XNScenarioManager.h @@ -76,4 +76,21 @@ public: * @return false: 解析失败 */ virtual bool AnalysisScenarioXml(const std::string &XmlPath, uint32_t initialType); + +private: + /** + * @brief 解析运行环境配置文件 + * @param XmlPath: std::string类型,运行环境配置文件解析路径 + * @return true: 解析成功 + * @return false: 解析失败 + */ + bool ParseScenarioXml(const std::string &XmlPath); + + /** + * @brief 解析构型配置文件 + * @param ConfigID: std::string类型,构型配置文件在数据库中的ID + * @return true: 解析成功 + * @return false: 解析失败 + */ + bool ParseConfig(const std::string &ConfigID); }; diff --git a/Release/include/XNCore/XNServiceManager.h b/Release/include/XNCore/XNServiceManager.h index eb0a5bb..a736a7f 100644 --- a/Release/include/XNCore/XNServiceManager.h +++ b/Release/include/XNCore/XNServiceManager.h @@ -29,7 +29,7 @@ public: virtual bool Initialize() override; virtual bool PrepareForExecute() override; void LoadService(const std::string &servicePath, const std::string &serviceName, - uint32_t initialType); + const std::string &serviceVersion, uint32_t initialType); public: XNServiceObjectPtr GetService(uint32_t serviceID); diff --git a/Release/include/XNCore/XNServiceObject.h b/Release/include/XNCore/XNServiceObject.h index 163be32..c01ff25 100644 --- a/Release/include/XNCore/XNServiceObject.h +++ b/Release/include/XNCore/XNServiceObject.h @@ -54,6 +54,10 @@ public: protected: XNFrameworkPtr GetFramework() const; + +private: + void ParseXml(); + void ParseConfig(); }; XNCLASS_PTR_DECLARE(XNServiceObject) diff --git a/Release/include/XNCore/XNServiceObject_p.h b/Release/include/XNCore/XNServiceObject_p.h index a9c4bb4..426dd33 100644 --- a/Release/include/XNCore/XNServiceObject_p.h +++ b/Release/include/XNCore/XNServiceObject_p.h @@ -11,4 +11,5 @@ struct XNServiceObjectPrivate : public XNObjectPrivate { std::unordered_map _dataWriters; XNFrameworkPtr pFramework; uint32_t _initialType; + XN_JSON _otherParams; }; diff --git a/XNCore/CMakeLists.txt b/XNCore/CMakeLists.txt index c0089d9..9d0efd4 100755 --- a/XNCore/CMakeLists.txt +++ b/XNCore/CMakeLists.txt @@ -16,8 +16,10 @@ endif() file(GLOB DDS_XNIDL_SOURCES_CXX "XNIDL/*.cxx") +find_package(nlohmann_json REQUIRED) find_package(Threads REQUIRED) find_package(OpenSSL REQUIRED) +find_package(SQLite3 REQUIRED) add_library(XNCore SHARED XNCore_global.h @@ -76,6 +78,7 @@ target_link_libraries(XNCore PRIVATE pthread OpenSSL::SSL OpenSSL::Crypto + nlohmann_json dl ) diff --git a/XNCore/XNCore_Function.cpp b/XNCore/XNCore_Function.cpp index 0106209..77b3be8 100644 --- a/XNCore/XNCore_Function.cpp +++ b/XNCore/XNCore_Function.cpp @@ -1,5 +1,7 @@ #include "XNCore_global.h" +namespace XNSim +{ XNTimePoint parseISOTime(const std::string &timeStr) { std::tm tm = {}; @@ -7,4 +9,50 @@ XNTimePoint parseISOTime(const std::string &timeStr) ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"); auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm)); return tp; -} \ No newline at end of file +} + +// 辅助函数:分割字符串 +std::vector split(const std::string &str, const std::string &delim) +{ + std::vector tokens; + size_t prev = 0, pos = 0; + do { + pos = str.find(delim, prev); + if (pos == std::string::npos) + pos = str.length(); + std::string token = str.substr(prev, pos - prev); + if (!token.empty()) + tokens.push_back(token); + prev = pos + delim.length(); + } while (pos < str.length() && prev < str.length()); + return tokens; +} + +// 辅助函数:获取文件名(不含扩展名) +std::string getFileNameWithoutExt(const std::string &path) +{ + size_t lastDot = path.find_last_of('.'); + if (lastDot != std::string::npos) { + return path.substr(0, lastDot); + } + return path; +} + +/** + * @brief 安全地将字符串转换为整数 + * @param str 要转换的字符串 + * @param defaultValue 转换失败时的默认值 + * @return 转换后的整数值 + */ +int safe_stoi(const std::string &str, int defaultValue) +{ + if (str.empty()) { + return defaultValue; + } + try { + return std::stoi(str); + } catch (const std::exception &) { + return defaultValue; + } +} +} // namespace XNSim \ No newline at end of file diff --git a/XNCore/XNCore_global.h b/XNCore/XNCore_global.h index b4ce4bb..e2cae8a 100755 --- a/XNCore/XNCore_global.h +++ b/XNCore/XNCore_global.h @@ -40,6 +40,8 @@ # include # include # include +# include +# include #endif #include @@ -53,6 +55,8 @@ #include #define FAST_DDS_MACRO eprosima::fastdds::dds +using XN_JSON = nlohmann::json; + /** * @brief 默认基频定义,单位 Hz */ @@ -91,13 +95,6 @@ struct PERIOD_INFO { */ using XNTimePoint = std::chrono::system_clock::time_point; -/** - * @brief 将ISO格式的时间字符串转换为系统时间点 - * @param timeStr ISO格式的时间字符串 (YYYY-MM-DDTHH:mm:ss) - * @return 系统时间点 - */ -extern "C" XNTimePoint XNCORE_EXPORT parseISOTime(const std::string &timeStr); - /** * @brief 系统运行状态枚举类 */ @@ -258,3 +255,37 @@ public: public: \ using ThisType = cls; \ using SuperType = sup; + +#define XN_UNUSED(x) (void)x + +namespace XNSim +{ +template +constexpr typename std::underlying_type::type enumValue(T e) +{ + return static_cast::type>(e); +} + +/** + * @brief 将ISO格式的时间字符串转换为系统时间点 + * @param timeStr ISO格式的时间字符串 (YYYY-MM-DDTHH:mm:ss) + * @return 系统时间点 + */ +extern "C" XNTimePoint XNCORE_EXPORT parseISOTime(const std::string &timeStr); + +extern "C" std::vector XNCORE_EXPORT split(const std::string &str, + const std::string &delim); + +extern "C" std::string XNCORE_EXPORT getFileNameWithoutExt(const std::string &path); + +extern "C" int XNCORE_EXPORT safe_stoi(const std::string &str, int defaultValue = 0); + +inline std::string getStringFromSqlite3(sqlite3_stmt *stmt, int column) +{ + const char *text = reinterpret_cast(sqlite3_column_text(stmt, column)); + if (text == nullptr) { + return ""; + } + return std::string(text); +} +} // namespace XNSim diff --git a/XNCore/XNFramework_p.h b/XNCore/XNFramework_p.h index cb27a74..2d648c4 100755 --- a/XNCore/XNFramework_p.h +++ b/XNCore/XNFramework_p.h @@ -77,4 +77,9 @@ struct XNFrameworkPrivate : public XNObjectPrivate { * @brief 场景XML */ std::string scenarioXml; + + /** + * @brief 构型ID + */ + uint32_t configId; }; diff --git a/XNCore/XNModelManager.cpp b/XNCore/XNModelManager.cpp index 5d3c2ff..b4008fd 100755 --- a/XNCore/XNModelManager.cpp +++ b/XNCore/XNModelManager.cpp @@ -55,6 +55,7 @@ bool XNModelManager::Initialize() } void XNModelManager::LoadModel(const std::string &modelPath, const std::string &className, + const std::string &modelVersion, const std::string &planeName, uint32_t initialType, uint32_t threadID) { T_D(); @@ -77,10 +78,15 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string & model->SetFramework(GetFramework()); model->SetInitializeType(initialType); model->SetThreadID(threadID); - // 使用std::filesystem处理路径 - std::filesystem::path configPath = - std::filesystem::path(modelPath).parent_path() / (className + ".mcfg"); - model->SetXmlPath(configPath.string()); + if (initialType == 0) { + // 使用std::filesystem处理路径 + std::filesystem::path configPath = + std::filesystem::path(modelPath).parent_path() + / (className + "_V" + modelVersion + ".mcfg"); + model->SetXmlPath(configPath.string()); + } else if (initialType == 1) { + model->SetXmlPath(planeName + "," + className + "," + modelVersion); + } // 注册模型到管理器 d->ModelMap[modelID] = model; @@ -92,9 +98,10 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string & if (threadID != 0) { auto framework = GetFramework(); if (framework) { - framework->GetThreadManager()->RegisterFunction( - modelID, std::bind(&XNModelObject::StepUpdate, model.get()), threadID, - model->GetRunFreq(), model->GetRunNode(), model->GetRunPriority()); + // 注册到线程管理器 (重复注册了,暂删除) + // framework->GetThreadManager()->RegisterFunction( + // modelID, std::bind(&XNModelObject::StepUpdate, model.get()), threadID, + // model->GetRunFreq(), model->GetRunNode(), model->GetRunPriority()); // 设置模型设置频率 double threadFreq = framework->GetThreadManager()->GetThreadFreqByID(threadID); diff --git a/XNCore/XNModelManager.h b/XNCore/XNModelManager.h index 4c030b6..b1c6a67 100755 --- a/XNCore/XNModelManager.h +++ b/XNCore/XNModelManager.h @@ -61,10 +61,14 @@ public: * @brief 加载模型 * @param modelPath: QString类型,模型动态链接库路径 * @param className: QString类型,模型类名 + * @param modelVersion: QString类型,模型版本号 + * @param initialType: UINT32类型,初始化类型 + * @param threadID: UINT32类型,线程ID * @details 加载模型 */ - void LoadModel(const std::string &modelPath, const std::string &className, uint32_t initialType, - uint32_t threadID); + void LoadModel(const std::string &modelPath, const std::string &className, + const std::string &modelVersion, const std::string &planeName, + uint32_t initialType, uint32_t threadID); /** * @brief 注册模型信息 diff --git a/XNCore/XNModelObject.cpp b/XNCore/XNModelObject.cpp index ccc2409..e697210 100755 --- a/XNCore/XNModelObject.cpp +++ b/XNCore/XNModelObject.cpp @@ -195,102 +195,210 @@ void XNModelObject::SetSetFreq(double setFreq) // 初始化函数 void XNModelObject::Initialize() { - // 先尝试调取动态库 T_D(); if (d->_initialType == 0) { - // 读取配置文件,设置循环执行函数 - std::ifstream file(GetXmlPath()); - if (!file.is_open()) { - LOG_WARNING("0x2161 Failed to open the model configuration file: %1!", GetXmlPath()); - return; - } - tinyxml2::XMLDocument doc; - doc.LoadFile(GetXmlPath().c_str()); - tinyxml2::XMLElement *rootNode = doc.FirstChildElement("Model"); - if (!rootNode) { - LOG_WARNING("0x2161 Failed to parse model configuration file: %1!", GetXmlPath()); - return; - } - // 读取配置文件的模型参数 - const char *modelName = rootNode->FirstChildElement("Name")->GetText(); - if (!modelName || std::string(modelName) != GetObjectName()) { - LOG_WARNING( - "0x2162 The model name in the configuration file of model %1 is not consistent " - "with the model name in the configuration file of model %2!", - GetObjectName(), modelName ? modelName : "null"); - return; - } - d->_sDescription = rootNode->FirstChildElement("Description")->GetText(); - d->_sAuthor = rootNode->FirstChildElement("Author")->GetText(); - d->_sVersion = rootNode->FirstChildElement("Version")->GetText(); + ParseXml(); + } else { + ParseConfig(); + } +} - // 使用标准C++时间处理 - std::string createTimeStr = rootNode->FirstChildElement("CreateTime")->GetText(); - std::string changeTimeStr = rootNode->FirstChildElement("ChangeTime")->GetText(); - d->_cCreatTime = parseISOTime(createTimeStr); - d->_cChangeTime = parseISOTime(changeTimeStr); +void XNModelObject::ParseXml() +{ + T_D(); + // 读取配置文件,设置循环执行函数 + std::ifstream file(GetXmlPath()); + if (!file.is_open()) { + LOG_WARNING("0x2161 Failed to open the model configuration file: %1!", GetXmlPath()); + return; + } + tinyxml2::XMLDocument doc; + doc.LoadFile(GetXmlPath().c_str()); + tinyxml2::XMLElement *rootNode = doc.FirstChildElement("Model"); + if (!rootNode) { + LOG_WARNING("0x2161 Failed to parse model configuration file: %1!", GetXmlPath()); + return; + } + // 读取配置文件的模型参数 + const char *modelName = rootNode->FirstChildElement("Name")->GetText(); + if (!modelName || std::string(modelName) != GetObjectName()) { + LOG_WARNING("0x2162 The model name in the configuration file of model %1 is not consistent " + "with the model name in the configuration file of model %2!", + GetObjectName(), modelName ? modelName : "null"); + return; + } + d->_sDescription = rootNode->FirstChildElement("Description")->GetText(); + d->_sAuthor = rootNode->FirstChildElement("Author")->GetText(); + d->_sVersion = rootNode->FirstChildElement("Version")->GetText(); - std::string funcNode = rootNode->FirstChildElement("Node")->GetText(); - d->_runPriority = std::stoi(rootNode->FirstChildElement("Priority")->GetText()); + // 使用标准C++时间处理 + std::string createTimeStr = rootNode->FirstChildElement("CreateTime")->GetText(); + std::string changeTimeStr = rootNode->FirstChildElement("ChangeTime")->GetText(); + d->_cCreatTime = XNSim::parseISOTime(createTimeStr); + d->_cChangeTime = XNSim::parseISOTime(changeTimeStr); - // 检查运行节点是否是 "x-x" 形式 - size_t tmp = funcNode.find('-'); - if (tmp == std::string::npos || tmp == 0) { - LOG_WARNING( - "0x2162 The value of the run node attribute in the configuration file of model " - "%1 is not in the x-x format, registration not executed!", - GetObjectName()); - return; - } + std::string funcNode = rootNode->FirstChildElement("Node")->GetText(); + d->_runPriority = XNSim::safe_stoi(rootNode->FirstChildElement("Priority")->GetText()); - // 使用标准C++字符串处理 - d->_runFreq = std::stoi(funcNode.substr(0, tmp)); - d->_runNode = std::stoi(funcNode.substr(tmp + 1)); + // 检查运行节点是否是 "x-x" 形式 + size_t tmp = funcNode.find('-'); + if (tmp == std::string::npos || tmp == 0) { + LOG_WARNING("0x2162 The value of the run node attribute in the configuration file of model " + "%1 is not in the x-x format, registration not executed!", + GetObjectName()); + return; + } - // 注册周期性函数 - auto framework = GetFramework(); - if (framework) { - auto threadManager = framework->GetThreadManager(); - if (threadManager) { - threadManager->RegisterFunction( - GetUniqueId(), std::bind(&XNModelObject::StepUpdate, this), d->_threadID, - d->_runFreq, d->_runNode, d->_runPriority); - } - } + // 使用标准C++字符串处理 + d->_runFreq = XNSim::safe_stoi(funcNode.substr(0, tmp)); + d->_runNode = XNSim::safe_stoi(funcNode.substr(tmp + 1)); - // 加载动态库 - const char *mathlib = rootNode->FirstChildElement("MathLib")->GetText(); - if (mathlib && strlen(mathlib) > 0) { - // 使用标准C++文件路径处理 - std::filesystem::path xmlPath(GetXmlPath()); - d->_sLibPath = xmlPath.parent_path().string() + "/" + mathlib; - - // 使用标准C++动态库加载 - d->_dynamicLib = dlopen(d->_sLibPath.c_str(), RTLD_LAZY); - if (d->_dynamicLib) { // 动态库加载成功 - LOG_INFO("0x2163 Model %1 loaded algorithm dynamic library %2 successfully!", - GetObjectName(), d->_sLibPath); - } else { - LOG_WARNING( - "0x2160 Model %1 failed to find algorithm dynamic library %2, will not call " - "algorithm!", - GetObjectName(), d->_sLibPath); - d->_dynamicLib = nullptr; - } - } - - // 处理指令列表 - tinyxml2::XMLElement *nodeCmds = rootNode->FirstChildElement("CommandList"); - if (nodeCmds) { - for (tinyxml2::XMLElement *nodeCmd = nodeCmds->FirstChildElement("Command"); - nodeCmd != nullptr; nodeCmd = nodeCmd->NextSiblingElement("Command")) { - const char *cmdName = nodeCmd->Attribute("Name"); - const char *cmdDescription = nodeCmd->Attribute("Description"); - const char *cmdCall = nodeCmd->Attribute("Call"); - // TODO: 处理命令列表 - } + // 注册周期性函数 + auto framework = GetFramework(); + if (framework) { + auto threadManager = framework->GetThreadManager(); + if (threadManager) { + threadManager->RegisterFunction( + GetUniqueId(), std::bind(&XNModelObject::StepUpdate, this), d->_threadID, + d->_runFreq, d->_runNode, d->_runPriority); } } + + // 加载动态库 + const char *mathlib = rootNode->FirstChildElement("MathLib")->GetText(); + if (mathlib && strlen(mathlib) > 0) { + // 使用标准C++文件路径处理 + std::filesystem::path xmlPath(GetXmlPath()); + d->_sLibPath = xmlPath.parent_path().string() + "/" + mathlib; + + // 使用标准C++动态库加载 + d->_dynamicLib = dlopen(d->_sLibPath.c_str(), RTLD_LAZY); + if (d->_dynamicLib) { // 动态库加载成功 + LOG_INFO("0x2163 Model %1 loaded algorithm dynamic library %2 successfully!", + GetObjectName(), d->_sLibPath); + } else { + LOG_WARNING( + "0x2160 Model %1 failed to find algorithm dynamic library %2, will not call " + "algorithm!", + GetObjectName(), d->_sLibPath); + d->_dynamicLib = nullptr; + } + } + + // 处理指令列表 + tinyxml2::XMLElement *nodeCmds = rootNode->FirstChildElement("CommandList"); + if (nodeCmds) { + for (tinyxml2::XMLElement *nodeCmd = nodeCmds->FirstChildElement("Command"); + nodeCmd != nullptr; nodeCmd = nodeCmd->NextSiblingElement("Command")) { + const char *cmdName = nodeCmd->Attribute("Name"); + const char *cmdDescription = nodeCmd->Attribute("Description"); + const char *cmdCall = nodeCmd->Attribute("Call"); + // TODO: 处理命令列表 + } + } +} + +void XNModelObject::ParseConfig() +{ + T_D(); + std::vector nameAndVersion = XNSim::split(GetXmlPath(), ","); + std::string planeName = nameAndVersion[0]; + std::string modelName = nameAndVersion[1]; + std::string modelVersion = nameAndVersion[2]; + // 获取数据库路径 + std::string dbPath = std::getenv("XNCore"); + if (dbPath.empty()) { + LOG_ERROR("0x1015 未设置XNCore环境变量, 引擎将退出!"); + return; + } + dbPath += "/database/XNSim.db"; + + // 打开数据库 + sqlite3 *db; + if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) { + LOG_ERROR("0x1016 打开数据库失败: %1", sqlite3_errmsg(db)); + return; + } + + // 准备SQL语句 + std::string sql = + "SELECT * FROM XNModelsVersion WHERE PlaneName = ? AND ClassName = ? AND Version = ?"; + 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; + } + + // 绑定参数 + if (sqlite3_bind_text(stmt, 1, planeName.c_str(), planeName.length(), nullptr) != SQLITE_OK + || sqlite3_bind_text(stmt, 2, modelName.c_str(), modelName.length(), nullptr) != SQLITE_OK + || sqlite3_bind_text(stmt, 3, modelVersion.c_str(), modelVersion.length(), nullptr) + != SQLITE_OK) { + LOG_ERROR("0x1018 绑定参数失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + sqlite3_close(db); + return; + } + + // 执行查询 + if (sqlite3_step(stmt) != SQLITE_ROW) { + LOG_ERROR("0x1019 未找到机型为%1,模型名称为%2,版本号%3的记录", planeName.c_str(), + modelName.c_str(), modelVersion.c_str()); + sqlite3_finalize(stmt); + sqlite3_close(db); + return; + } + + d->_sDescription = XNSim::getStringFromSqlite3(stmt, 7); + d->_sAuthor = XNSim::getStringFromSqlite3(stmt, 6); + d->_sVersion = XNSim::getStringFromSqlite3(stmt, 2); + + // 解析时间 + std::string createTimeStr = XNSim::getStringFromSqlite3(stmt, 8); + std::string changeTimeStr = XNSim::getStringFromSqlite3(stmt, 9); + d->_cCreatTime = XNSim::parseISOTime(createTimeStr); + d->_cChangeTime = XNSim::parseISOTime(changeTimeStr); + d->_runFreq = XNSim::safe_stoi(XNSim::getStringFromSqlite3(stmt, 10)); + d->_runNode = XNSim::safe_stoi(XNSim::getStringFromSqlite3(stmt, 11)); + d->_runPriority = XNSim::safe_stoi(XNSim::getStringFromSqlite3(stmt, 12)); + + // 注册周期性函数 + auto framework = GetFramework(); + if (framework) { + auto threadManager = framework->GetThreadManager(); + if (threadManager) { + threadManager->RegisterFunction( + GetUniqueId(), std::bind(&XNModelObject::StepUpdate, this), d->_threadID, + d->_runFreq, d->_runNode, d->_runPriority); + } + } + + // 加载动态库 + std::string mathlib = XNSim::getStringFromSqlite3(stmt, 13); + if (mathlib.length() > 0) { + // 使用标准C++文件路径处理 + std::filesystem::path xmlPath(GetXmlPath()); + d->_sLibPath = xmlPath.parent_path().string() + "/" + mathlib; + + // 使用标准C++动态库加载 + d->_dynamicLib = dlopen(d->_sLibPath.c_str(), RTLD_LAZY); + if (d->_dynamicLib) { // 动态库加载成功 + LOG_INFO("0x2163 Model %1 loaded algorithm dynamic library %2 successfully!", + GetObjectName(), d->_sLibPath); + } else { + LOG_WARNING( + "0x2160 Model %1 failed to find algorithm dynamic library %2, will not call " + "algorithm!", + GetObjectName(), d->_sLibPath); + d->_dynamicLib = nullptr; + } + } + + // TODO: 读取模型命令列表 + // 清理资源 + sqlite3_finalize(stmt); + sqlite3_close(db); } // 单步执行函数 diff --git a/XNCore/XNModelObject.h b/XNCore/XNModelObject.h index 540781a..2f7153f 100755 --- a/XNCore/XNModelObject.h +++ b/XNCore/XNModelObject.h @@ -238,6 +238,10 @@ public: public: virtual void RegisterDDSParticipant(); + +private: + void ParseXml(); + void ParseConfig(); }; #define XN_MODEL_INITIALIZE(ClassName) \ diff --git a/XNCore/XNScenarioManager.cpp b/XNCore/XNScenarioManager.cpp index 68e1070..468fdbd 100755 --- a/XNCore/XNScenarioManager.cpp +++ b/XNCore/XNScenarioManager.cpp @@ -66,35 +66,19 @@ bool XNScenarioManager::PrepareForExecute() return true; } -// 辅助函数:分割字符串 -std::vector split(const std::string &str, const std::string &delim) -{ - std::vector tokens; - size_t prev = 0, pos = 0; - do { - pos = str.find(delim, prev); - if (pos == std::string::npos) - pos = str.length(); - std::string token = str.substr(prev, pos - prev); - if (!token.empty()) - tokens.push_back(token); - prev = pos + delim.length(); - } while (pos < str.length() && prev < str.length()); - return tokens; -} - -// 辅助函数:获取文件名(不含扩展名) -std::string getFileNameWithoutExt(const std::string &path) -{ - size_t lastDot = path.find_last_of('.'); - if (lastDot != std::string::npos) { - return path.substr(0, lastDot); - } - return path; -} - // 运行环境配置文件解析 bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t initialType) +{ + T_D(); + if (initialType == 0) { + return ParseScenarioXml(XmlPath); + } else { + return ParseConfig(XmlPath); + } +} + +// 解析运行环境描述文件 +bool XNScenarioManager::ParseScenarioXml(const std::string &XmlPath) { T_D(); std::ifstream file(XmlPath); @@ -114,6 +98,7 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t std::string OSName = envInfo->Attribute("OSName"); std::string version = envInfo->Attribute("Version"); std::string kernel = envInfo->Attribute("RTXVersion"); + std::string planeName = envInfo->Attribute("PlaneName"); // 设置工作目录 std::string rootPath = envInfo->Attribute("WorkPath"); GetFramework()->SetWorkPath(rootPath); @@ -128,7 +113,7 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t GetFramework()->GetDDSManager()->SetDomainID(domainID); // 读取CPU亲和性 std::string cpuAff = envInfo->Attribute("CPUAffinity"); - std::vector cpuAffList = split(cpuAff, ","); + std::vector cpuAffList = XNSim::split(cpuAff, ","); //读取服务列表 tinyxml2::XMLElement *serviceList = root->FirstChildElement("ServicesList"); @@ -137,10 +122,12 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t while (service) { std::string serviceName = service->Attribute("Name"); std::string libName = service->Attribute("ClassName"); - libName = getFileNameWithoutExt(libName); - std::string dynamicLibName = servicePath + "lib" + libName + ".so"; + std::string serviceVersion = service->Attribute("Version"); + libName = XNSim::getFileNameWithoutExt(libName); + std::string dynamicLibName = servicePath + "lib" + libName + ".so." + serviceVersion; // 加载动态库 - GetFramework()->GetServiceManager()->LoadService(dynamicLibName, libName, 0); + GetFramework()->GetServiceManager()->LoadService(dynamicLibName, libName, + serviceVersion, 0); service = service->NextSiblingElement("Service"); } } @@ -153,14 +140,14 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t // 读取模型分组频率 double modelGroupFreq = std::stod(modelGroup->Attribute("Freq")); // 读取模型分组优先级 - int modelGroupPriority = std::stoi(modelGroup->Attribute("Priority")); + int modelGroupPriority = XNSim::safe_stoi(modelGroup->Attribute("Priority")); if (modelGroupPriority > 99 || modelGroupPriority < 0) { LOG_ERROR("0x2100 模型分组优先级设置错误,优先级值:%d", modelGroupPriority); return false; } // 读取模型分组CPU亲和性 std::string modelGroupCPUAff = modelGroup->Attribute("CPUAff"); - std::vector modelGroupCPUAffList = split(modelGroupCPUAff, ","); + std::vector modelGroupCPUAffList = XNSim::split(modelGroupCPUAff, ","); // 验证CPU亲和性 for (const auto &cpu : modelGroupCPUAffList) { @@ -188,10 +175,12 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t while (model) { std::string modelName = model->Attribute("Name"); std::string libName = model->Attribute("ClassName"); - libName = getFileNameWithoutExt(libName); - std::string dynamicLibName = modelPath + "lib" + libName + ".so"; + std::string modelVersion = model->Attribute("Version"); + libName = XNSim::getFileNameWithoutExt(libName); + std::string dynamicLibName = modelPath + "lib" + libName + ".so." + modelVersion; // 加载动态库 - GetFramework()->GetModelManager()->LoadModel(dynamicLibName, libName, 0, threadID); + GetFramework()->GetModelManager()->LoadModel(dynamicLibName, libName, modelVersion, + planeName, 0, threadID); model = model->NextSiblingElement("Model"); } @@ -200,3 +189,204 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t return true; } + +// 解析构型配置文件 +bool XNScenarioManager::ParseConfig(const std::string &ConfigID) +{ + T_D(); + // 获取数据库路径 + 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 = XNSim::safe_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; + } + std::string planeName = XNSim::getStringFromSqlite3(stmt, 1); + std::string osName = XNSim::getStringFromSqlite3(stmt, 3); + std::string version = XNSim::getStringFromSqlite3(stmt, 4); + std::string kernel = XNSim::getStringFromSqlite3(stmt, 5); + std::string rootPath = XNSim::getStringFromSqlite3(stmt, 7); + GetFramework()->SetWorkPath(rootPath); + // 设置模型库目录 + std::string modelPath = rootPath + XNSim::getStringFromSqlite3(stmt, 8); + GetFramework()->SetModelPath(modelPath); + // 设置服务库目录 + std::string servicePath = rootPath + XNSim::getStringFromSqlite3(stmt, 9); + GetFramework()->SetServicePath(servicePath); + // 设置域ID + uint32_t domainID = std::stoul(XNSim::getStringFromSqlite3(stmt, 10)); + GetFramework()->GetDDSManager()->SetDomainID(domainID); + // 读取CPU亲和性 + std::string cpuAff = XNSim::getStringFromSqlite3(stmt, 6); + std::vector cpuAffList = XNSim::split(cpuAff, ","); + + //查询LoadServices表读取服务信息 + std::string servicesSql = "SELECT * FROM LoadServices WHERE ConfID = ?"; + sqlite3_stmt *servicesStmt; + if (sqlite3_prepare_v2(db, servicesSql.c_str(), -1, &servicesStmt, nullptr) != SQLITE_OK) { + LOG_ERROR("0x1020 准备LoadServices查询语句失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + // 绑定参数 + if (sqlite3_bind_int(servicesStmt, 1, configIdInt) != SQLITE_OK) { + LOG_ERROR("0x1021 绑定LoadServices参数失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + + // 执行查询并处理结果 + while (sqlite3_step(servicesStmt) == SQLITE_ROW) { + // 获取服务信息 + std::string ClassName = XNSim::getStringFromSqlite3(servicesStmt, 1); + std::string ServiceVersion = XNSim::getStringFromSqlite3(servicesStmt, 2); + std::string ServiceName = XNSim::getStringFromSqlite3(servicesStmt, 3); + + ClassName = XNSim::getFileNameWithoutExt(ClassName); + std::string dynamicLibName = servicePath + "lib" + ClassName + ".so." + ServiceVersion; + // 加载动态库 + GetFramework()->GetServiceManager()->LoadService(dynamicLibName, ClassName, ServiceVersion, + 1); + } + + // 查询LoadModelGroups表读取模型组信息 + std::string modelGroupsSql = "SELECT * FROM LoadModelGroups WHERE ConfID = ?"; + sqlite3_stmt *modelGroupsStmt; + if (sqlite3_prepare_v2(db, modelGroupsSql.c_str(), -1, &modelGroupsStmt, nullptr) + != SQLITE_OK) { + LOG_ERROR("0x1020 准备LoadModelGroups查询语句失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + + // 绑定参数 + if (sqlite3_bind_int(modelGroupsStmt, 1, configIdInt) != SQLITE_OK) { + LOG_ERROR("0x1021 绑定LoadModelGroups参数失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(modelGroupsStmt); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + + // 执行查询并处理结果 + while (sqlite3_step(modelGroupsStmt) == SQLITE_ROW) { + // 获取模型组信息 + std::string GroupID = XNSim::getStringFromSqlite3(modelGroupsStmt, 1); + std::string GroupName = XNSim::getStringFromSqlite3(modelGroupsStmt, 2); + double GroupFreq = std::stod(XNSim::getStringFromSqlite3(modelGroupsStmt, 3)); + uint32_t GroupPriority = XNSim::safe_stoi(XNSim::getStringFromSqlite3(modelGroupsStmt, 4)); + std::string GroupCPUAff = XNSim::getStringFromSqlite3(modelGroupsStmt, 5); + std::vector GroupCPUAffList = XNSim::split(GroupCPUAff, ","); + + // 验证CPU亲和性 + for (const auto &cpu : GroupCPUAffList) { + if (std::find(cpuAffList.begin(), cpuAffList.end(), cpu) == cpuAffList.end()) { + LOG_ERROR("0x2100 模型分组CPU亲和性设置错误,CPU亲和性值:%s,进程CPU亲和性值:%s", + cpu.c_str(), cpuAff.c_str()); + sqlite3_finalize(modelGroupsStmt); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + } + + int ThreadCpuAffinity = 0; + for (const auto &cpu : GroupCPUAffList) { + auto it = std::find(cpuAffList.begin(), cpuAffList.end(), cpu); + if (it != cpuAffList.end()) { + ThreadCpuAffinity |= 1 << std::distance(cpuAffList.begin(), it); + } + } + LOG_INFO("0x1021 添加线程池: %1", GroupName); + // 添加线程池 + uint32_t threadID = GetFramework()->GetThreadManager()->AddThreadPool( + GroupName, GroupFreq, GroupPriority, ThreadCpuAffinity); + + // 准备查询LoadModels表的SQL语句 + std::string modelsSql = "SELECT * FROM LoadModels WHERE GroupID = ?"; + sqlite3_stmt *modelsStmt = nullptr; + if (sqlite3_prepare_v2(db, modelsSql.c_str(), -1, &modelsStmt, nullptr) != SQLITE_OK) { + LOG_ERROR("0x1022 准备LoadModels查询语句失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(modelGroupsStmt); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + + // 绑定参数 + if (sqlite3_bind_int(modelsStmt, 1, XNSim::safe_stoi(GroupID)) != SQLITE_OK) { + LOG_ERROR("0x1023 绑定LoadModels参数失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(modelsStmt); + sqlite3_finalize(modelGroupsStmt); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + + // 执行查询并处理结果 + while (sqlite3_step(modelsStmt) == SQLITE_ROW) { + // 获取模型信息 + std::string ClassName = XNSim::getStringFromSqlite3(modelsStmt, 1); + std::string ModelVersion = XNSim::getStringFromSqlite3(modelsStmt, 2); + std::string ModelName = XNSim::getStringFromSqlite3(modelsStmt, 3); + + ClassName = XNSim::getFileNameWithoutExt(ClassName); + std::string dynamicLibName = modelPath + "lib" + ClassName + ".so." + ModelVersion; + // 加载动态库 + LOG_INFO("0x1021 加载模型: %1", dynamicLibName); + GetFramework()->GetModelManager()->LoadModel(dynamicLibName, ClassName, ModelVersion, + planeName, 1, threadID); + } + // 清理资源 + sqlite3_finalize(modelsStmt); + } + + // 清理资源 + sqlite3_finalize(modelGroupsStmt); + sqlite3_finalize(servicesStmt); + sqlite3_finalize(stmt); + sqlite3_close(db); + return true; +} diff --git a/XNCore/XNScenarioManager.h b/XNCore/XNScenarioManager.h index 89a293b..b659e78 100755 --- a/XNCore/XNScenarioManager.h +++ b/XNCore/XNScenarioManager.h @@ -76,4 +76,21 @@ public: * @return false: 解析失败 */ virtual bool AnalysisScenarioXml(const std::string &XmlPath, uint32_t initialType); + +private: + /** + * @brief 解析运行环境配置文件 + * @param XmlPath: std::string类型,运行环境配置文件解析路径 + * @return true: 解析成功 + * @return false: 解析失败 + */ + bool ParseScenarioXml(const std::string &XmlPath); + + /** + * @brief 解析构型配置文件 + * @param ConfigID: std::string类型,构型配置文件在数据库中的ID + * @return true: 解析成功 + * @return false: 解析失败 + */ + bool ParseConfig(const std::string &ConfigID); }; diff --git a/XNCore/XNServiceManager.cpp b/XNCore/XNServiceManager.cpp index 4bdb00e..cdce8a4 100755 --- a/XNCore/XNServiceManager.cpp +++ b/XNCore/XNServiceManager.cpp @@ -38,7 +38,7 @@ bool XNServiceManager::PrepareForExecute() } void XNServiceManager::LoadService(const std::string &servicePath, const std::string &serviceName, - uint32_t initialType) + const std::string &serviceVersion, uint32_t initialType) { T_D(); void *handle = dlopen(servicePath.c_str(), RTLD_LAZY); @@ -59,15 +59,26 @@ void XNServiceManager::LoadService(const std::string &servicePath, const std::st service->SetUniqueId(serviceID); service->SetObjectName(serviceName); service->SetFramework(GetFramework()); - // 使用std::filesystem处理路径 - std::filesystem::path configPath = - std::filesystem::path(servicePath).parent_path() / (serviceName + ".scfg"); - service->SetXmlPath(configPath.string()); + if (initialType == 0) { + // 使用std::filesystem处理路径 + std::filesystem::path configPath = + std::filesystem::path(servicePath).parent_path() + / (serviceName + "_V" + serviceVersion + ".scfg"); + service->SetXmlPath(configPath.string()); + } else if (initialType == 1) { + LOG_INFO("0x2176 加载服务: %1", serviceName + "," + serviceVersion); + service->SetXmlPath(serviceName + "," + serviceVersion); + } else { + LOG_WARNING("0x2175 InitialType Error, InitialType: %d", initialType); + dlclose(handle); + return; + } // 注册服务到管理器 d->ServiceList[serviceID] = service; service->SetInitializeType(initialType); // 初始化服务 + LOG_INFO("0x2176 初始化服务: %1", serviceName); service->Initialize(); } else { LOG_WARNING("0x2173 Service %s Not found in dynamic link library %s!", diff --git a/XNCore/XNServiceManager.h b/XNCore/XNServiceManager.h index eb0a5bb..a736a7f 100755 --- a/XNCore/XNServiceManager.h +++ b/XNCore/XNServiceManager.h @@ -29,7 +29,7 @@ public: virtual bool Initialize() override; virtual bool PrepareForExecute() override; void LoadService(const std::string &servicePath, const std::string &serviceName, - uint32_t initialType); + const std::string &serviceVersion, uint32_t initialType); public: XNServiceObjectPtr GetService(uint32_t serviceID); diff --git a/XNCore/XNServiceObject.cpp b/XNCore/XNServiceObject.cpp index 8fd2626..15b6b63 100755 --- a/XNCore/XNServiceObject.cpp +++ b/XNCore/XNServiceObject.cpp @@ -139,51 +139,154 @@ void XNServiceObject::Initialize() { T_D(); if (d->_initialType == 0) { - tinyxml2::XMLDocument doc; - if (doc.LoadFile(GetXmlPath().c_str()) != tinyxml2::XML_SUCCESS) { - LOG_WARNING("Failed to open the service configuration file: %1!", GetXmlPath()); - return; - } - - tinyxml2::XMLElement *rootNode = doc.RootElement(); - if (!rootNode) { - LOG_WARNING("Invalid XML file format: %1!", GetXmlPath()); - return; - } - - const char *serviceName = rootNode->FirstChildElement("Name")->GetText(); - if (serviceName != GetObjectName()) { - LOG_WARNING( - "The service name in the configuration file of service %1 is not consistent " - "with the service name in the configuration file of service %2!", - GetObjectName(), serviceName); - return; - } - - d->_sDescription = rootNode->FirstChildElement("Description")->GetText(); - d->_sAuthor = rootNode->FirstChildElement("Author")->GetText(); - d->_sVersion = rootNode->FirstChildElement("Version")->GetText(); - - // 解析时间 - const char *createTimeStr = rootNode->FirstChildElement("CreateTime")->GetText(); - const char *changeTimeStr = rootNode->FirstChildElement("ChangeTime")->GetText(); - d->_cCreateTime = parseISOTime(createTimeStr); - d->_cChangeTime = parseISOTime(changeTimeStr); - - tinyxml2::XMLElement *nodeCmds = rootNode->FirstChildElement("CommandList"); - if (nodeCmds) { - for (tinyxml2::XMLElement *nodeCmd = nodeCmds->FirstChildElement("Command"); - nodeCmd != nullptr; nodeCmd = nodeCmd->NextSiblingElement("Command")) { - const char *cmdName = nodeCmd->Attribute("Name"); - const char *cmdDescription = nodeCmd->Attribute("Description"); - const char *cmdCall = nodeCmd->Attribute("Call"); - // TODO: 处理命令信息 - } - } + ParseXml(); } else { + ParseConfig(); } } +void XNServiceObject::ParseXml() +{ + T_D(); + tinyxml2::XMLDocument doc; + if (doc.LoadFile(GetXmlPath().c_str()) != tinyxml2::XML_SUCCESS) { + LOG_WARNING("Failed to open the service configuration file: %1!", GetXmlPath()); + return; + } + + tinyxml2::XMLElement *rootNode = doc.RootElement(); + if (!rootNode) { + LOG_WARNING("Invalid XML file format: %1!", GetXmlPath()); + return; + } + + const char *serviceName = rootNode->FirstChildElement("Name")->GetText(); + if (serviceName != GetObjectName()) { + LOG_WARNING("The service name in the configuration file of service %1 is not consistent " + "with the service name in the configuration file of service %2!", + GetObjectName(), serviceName); + return; + } + + d->_sDescription = rootNode->FirstChildElement("Description")->GetText(); + d->_sAuthor = rootNode->FirstChildElement("Author")->GetText(); + d->_sVersion = rootNode->FirstChildElement("Version")->GetText(); + + // 解析时间 + const char *createTimeStr = rootNode->FirstChildElement("CreateTime")->GetText(); + const char *changeTimeStr = rootNode->FirstChildElement("ChangeTime")->GetText(); + d->_cCreateTime = XNSim::parseISOTime(createTimeStr); + d->_cChangeTime = XNSim::parseISOTime(changeTimeStr); + + tinyxml2::XMLElement *nodeCmds = rootNode->FirstChildElement("CommandList"); + if (nodeCmds) { + for (tinyxml2::XMLElement *nodeCmd = nodeCmds->FirstChildElement("Command"); + nodeCmd != nullptr; nodeCmd = nodeCmd->NextSiblingElement("Command")) { + const char *cmdName = nodeCmd->Attribute("Name"); + const char *cmdDescription = nodeCmd->Attribute("Description"); + const char *cmdCall = nodeCmd->Attribute("Call"); + // TODO: 处理命令信息 + } + } +} + +void XNServiceObject::ParseConfig() +{ + T_D(); + std::vector nameAndVersion = XNSim::split(GetXmlPath(), ","); + std::string serviceName = nameAndVersion[0]; + std::string serviceVersion = nameAndVersion[1]; + // 获取数据库路径 + std::string dbPath = std::getenv("XNCore"); + if (dbPath.empty()) { + LOG_ERROR("0x1015 未设置XNCore环境变量, 引擎将退出!"); + return; + } + dbPath += "/database/XNSim.db"; + + // 打开数据库 + sqlite3 *db; + if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) { + LOG_ERROR("0x1016 打开数据库失败: %1", sqlite3_errmsg(db)); + return; + } + + // 准备SQL语句 + std::string sql = "SELECT * FROM XNServiceVersion WHERE ClassName = ? AND Version = ?"; + 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; + } + + // 绑定参数 + if (sqlite3_bind_text(stmt, 1, serviceName.c_str(), serviceName.length(), nullptr) != SQLITE_OK + || sqlite3_bind_text(stmt, 2, serviceVersion.c_str(), serviceVersion.length(), nullptr) + != SQLITE_OK) { + LOG_ERROR("0x1018 绑定参数失败: %1", sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + sqlite3_close(db); + return; + } + + // 执行查询 + if (sqlite3_step(stmt) != SQLITE_ROW) { + LOG_ERROR("0x1019 未找到服务名称为%1,版本号%2的记录", serviceName.c_str(), + serviceVersion.c_str()); + sqlite3_finalize(stmt); + sqlite3_close(db); + return; + } + d->_sDescription = XNSim::getStringFromSqlite3(stmt, 5); + d->_sAuthor = XNSim::getStringFromSqlite3(stmt, 4); + d->_sVersion = XNSim::getStringFromSqlite3(stmt, 2); + + // 解析时间 + std::string createTimeStr = XNSim::getStringFromSqlite3(stmt, 6); + std::string changeTimeStr = XNSim::getStringFromSqlite3(stmt, 7); + d->_cCreateTime = XNSim::parseISOTime(createTimeStr); + d->_cChangeTime = XNSim::parseISOTime(changeTimeStr); + + // 读取服务命令列表 + std::string commandListStr = XNSim::getStringFromSqlite3(stmt, 8); + if (!commandListStr.empty()) { + try { + XN_JSON commandList = XN_JSON::parse(commandListStr); + if (commandList.is_array()) { + for (const auto &cmd : commandList) { + if (cmd.contains("Name") && cmd.contains("Description") + && cmd.contains("Call")) { + LOG_INFO("0x1021 服务命令: %1", cmd["Name"].get()); + // TODO: 处理服务命令信息 + // d->_commandList.emplace_back( + // cmd["Name"].get(), + // cmd["Description"].get(), + // cmd["Call"].get() + // ); + } + } + } + } catch (const std::exception &e) { + LOG_WARNING("0x1020 解析服务命令列表失败: %1", e.what()); + } + } + + // 读取其他参数 + std::string otherParamsStr = XNSim::getStringFromSqlite3(stmt, 9); + if (!otherParamsStr.empty()) { + try { + d->_otherParams = XN_JSON::parse(otherParamsStr); + } catch (const std::exception &e) { + LOG_WARNING("0x1020 解析其他参数失败: %1", e.what()); + } + } + + // 清理资源 + sqlite3_finalize(stmt); + sqlite3_close(db); +} + void XNServiceObject::PrepareForExecute() { T_D(); diff --git a/XNCore/XNServiceObject.h b/XNCore/XNServiceObject.h index 163be32..c01ff25 100755 --- a/XNCore/XNServiceObject.h +++ b/XNCore/XNServiceObject.h @@ -54,6 +54,10 @@ public: protected: XNFrameworkPtr GetFramework() const; + +private: + void ParseXml(); + void ParseConfig(); }; XNCLASS_PTR_DECLARE(XNServiceObject) diff --git a/XNCore/XNServiceObject_p.h b/XNCore/XNServiceObject_p.h index a9c4bb4..426dd33 100755 --- a/XNCore/XNServiceObject_p.h +++ b/XNCore/XNServiceObject_p.h @@ -11,4 +11,5 @@ struct XNServiceObjectPrivate : public XNObjectPrivate { std::unordered_map _dataWriters; XNFrameworkPtr pFramework; uint32_t _initialType; + XN_JSON _otherParams; }; diff --git a/XNEngine/XNEngine.cpp b/XNEngine/XNEngine.cpp index e28c70c..7ec7439 100755 --- a/XNEngine/XNEngine.cpp +++ b/XNEngine/XNEngine.cpp @@ -403,24 +403,35 @@ void XNEngine::PublishEngineStatus() } // 运行引擎 -bool XNEngine::Run(const std::string &XmlPath) +bool XNEngine::Run(const std::string &XmlPath, const uint32_t InitializeType) { if (!framework) { return false; } - // 解析配置文件 - bool isReady = ParseConfig(XmlPath); - // 如果解析配置文件失败 - if (!isReady) { - // 返回失败 - 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(0); + bool ret = framework->Initialize(InitializeType); // 如果初始化失败 if (!ret) { LOG_ERROR("0x1012 初始化失败, 引擎将退出!"); @@ -488,7 +499,7 @@ bool XNEngine::Run(const std::string &XmlPath) } // 运行引擎 -bool XNEngine::ParseDataBase(const uint32_t &ConfigId) +bool XNEngine::ParseDataBase(const std::string &ConfigId) { // 获取数据库路径 std::string dbPath = std::getenv("XNCore"); @@ -501,7 +512,7 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId) // 打开数据库 sqlite3 *db; if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) { - LOG_ERROR("0x1016 打开数据库失败: {}", sqlite3_errmsg(db)); + LOG_ERROR("0x1016 打开数据库失败: %1", sqlite3_errmsg(db)); return false; } @@ -509,14 +520,15 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId) 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语句失败: {}", sqlite3_errmsg(db)); + LOG_ERROR("0x1017 准备SQL语句失败: %1", sqlite3_errmsg(db)); sqlite3_close(db); return false; } // 绑定参数 - if (sqlite3_bind_int(stmt, 1, ConfigId) != SQLITE_OK) { - LOG_ERROR("0x1018 绑定参数失败: {}", sqlite3_errmsg(db)); + 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; @@ -524,7 +536,7 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId) // 执行查询 if (sqlite3_step(stmt) != SQLITE_ROW) { - LOG_ERROR("0x1019 未找到配置ID为{}的记录", ConfigId); + LOG_ERROR("0x1019 未找到配置ID为%1的记录", ConfigId); sqlite3_finalize(stmt); sqlite3_close(db); return false; @@ -539,7 +551,8 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId) CPUAffinity = 0; // 读取配置信息 - std::string CPUAff = reinterpret_cast(sqlite3_column_text(stmt, 6)); + std::string CPUAff = XNSim::getStringFromSqlite3(stmt, 6); + //std::string CPUAff = reinterpret_cast(sqlite3_column_text(stmt, 6)); std::istringstream iss(CPUAff); std::string cpuIndex; @@ -591,88 +604,6 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId) sqlite3_close(db); return true; } - -bool XNEngine::Run(const uint32_t &ConfigId) -{ - if (!framework) { - return false; - } - // 解析数据库 - bool isReady = ParseDataBase(ConfigId); - // 如果解析数据库失败 - if (!isReady) { - // 返回失败 - return false; - } - // 设置构型ID - //framework->SetScenarioId(ConfigId); - // 设置CPU亲和性 - framework->SetCpuAffinity(CPUAffinity); - // 单次触发初始化信号 - bool ret = framework->Initialize(1); - // 如果初始化失败 - 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; -} // 设置测试模式 void XNEngine::SetTestMode(bool isTestMode) { diff --git a/XNEngine/XNEngine.h b/XNEngine/XNEngine.h index 8c0d66c..30f2a5a 100755 --- a/XNEngine/XNEngine.h +++ b/XNEngine/XNEngine.h @@ -40,13 +40,8 @@ public: * @param XmlPath 场景XML路径 * @return 是否成功 */ - bool Run(const std::string &XmlPath); - /** - * @brief 运行引擎 - * @param ConfigId 构型ID - * @return 是否成功 - */ - bool Run(const uint32_t &ConfigId); + bool Run(const std::string &XmlPath, const uint32_t InitializeType); + /** * @brief 设置测试模式 * @param isTestMode 是否为测试模式 @@ -66,7 +61,7 @@ private: * @param ConfigId 配置ID * @return 是否成功 */ - bool ParseDataBase(const uint32_t &ConfigId); + bool ParseDataBase(const std::string &ConfigId); /** * @brief 设置控制台输出 diff --git a/XNEngine/main.cpp b/XNEngine/main.cpp index d4acff3..38bafd9 100755 --- a/XNEngine/main.cpp +++ b/XNEngine/main.cpp @@ -72,9 +72,9 @@ int main(int argc, char *argv[]) //检测配置文件格式 if (hasConfigPath) { - return engine.Run(configPath); + return engine.Run(configPath, 0); } else if (hasConfigId) { - return engine.Run(configId); + return engine.Run(configId, 1); } return -1; } diff --git a/XNModels/XNATA04DataProcessor/CMakeLists.txt b/XNModels/XNATA04DataProcessor/CMakeLists.txt index a2b2903..bb44890 100755 --- a/XNModels/XNATA04DataProcessor/CMakeLists.txt +++ b/XNModels/XNATA04DataProcessor/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(XNATA04DataProcessor LANGUAGES CXX) +set(MODEL_VERSION "1.0.0.0") + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -23,6 +25,14 @@ add_library(XNATA04DataProcessor SHARED XNATA04DataProcessor_p.h ) +set_target_properties(XNATA04DataProcessor PROPERTIES + LIBRARY_OUTPUT_NAME "libXNATA04DataProcessor.so.${MODEL_VERSION}" + PREFIX "" + SUFFIX "" + SKIP_BUILD_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE +) + target_link_libraries(XNATA04DataProcessor PRIVATE ${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libC909_V1_Interface.so @@ -45,4 +55,7 @@ install(TARGETS XNATA04DataProcessor file(GLOB CONFIG_FILE "*.mcfg") # 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) +install(FILES ${CONFIG_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX} + RENAME "XNATA04DataProcessor_V${MODEL_VERSION}.mcfg" +) \ No newline at end of file diff --git a/XNModels/XNAerodynamics/CMakeLists.txt b/XNModels/XNAerodynamics/CMakeLists.txt index 6b1e005..ba3848a 100755 --- a/XNModels/XNAerodynamics/CMakeLists.txt +++ b/XNModels/XNAerodynamics/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(XNAerodynamics LANGUAGES CXX) +set(MODEL_VERSION "1.0.0.0") + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -24,6 +26,14 @@ add_library(XNAerodynamics SHARED XNAerodynamics_p.h ) +set_target_properties(XNAerodynamics PROPERTIES + LIBRARY_OUTPUT_NAME "libXNAerodynamics.so.${MODEL_VERSION}" + PREFIX "" + SUFFIX "" + SKIP_BUILD_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE +) + target_link_libraries(XNAerodynamics PRIVATE ${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libC909_V1_Interface.so @@ -47,4 +57,7 @@ install(TARGETS XNAerodynamics file(GLOB CONFIG_FILE "*.mcfg") # 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) +install(FILES ${CONFIG_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX} + RENAME "XNAerodynamics_V${MODEL_VERSION}.mcfg" +) diff --git a/XNModels/XNGroundHandling/CMakeLists.txt b/XNModels/XNGroundHandling/CMakeLists.txt index a38ba1c..bb5cc98 100755 --- a/XNModels/XNGroundHandling/CMakeLists.txt +++ b/XNModels/XNGroundHandling/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(XNGroundHandling LANGUAGES CXX) +set(MODEL_VERSION "1.0.0.0") + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -24,6 +26,14 @@ add_library(XNGroundHandling SHARED XNGroundHandling_p.h ) +set_target_properties(XNGroundHandling PROPERTIES + LIBRARY_OUTPUT_NAME "libXNGroundHandling.so.${MODEL_VERSION}" + PREFIX "" + SUFFIX "" + SKIP_BUILD_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE +) + target_link_libraries(XNGroundHandling PRIVATE ${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libC909_V1_Interface.so @@ -46,4 +56,7 @@ install(TARGETS XNGroundHandling file(GLOB CONFIG_FILE "*.mcfg") # 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) +install(FILES ${CONFIG_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX} + RENAME "XNGroundHandling_V${MODEL_VERSION}.mcfg" +) \ No newline at end of file diff --git a/XNModels/XNWeightBalance/CMakeLists.txt b/XNModels/XNWeightBalance/CMakeLists.txt index 27cf78b..03a0313 100755 --- a/XNModels/XNWeightBalance/CMakeLists.txt +++ b/XNModels/XNWeightBalance/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(XNWeightBalance LANGUAGES CXX) +set(MODEL_VERSION "1.0.0.0") + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -24,6 +26,14 @@ add_library(XNWeightBalance SHARED XNWeightBalance_p.h ) +set_target_properties(XNWeightBalance PROPERTIES + LIBRARY_OUTPUT_NAME "libXNWeightBalance.so.${MODEL_VERSION}" + PREFIX "" + SUFFIX "" + SKIP_BUILD_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE +) + target_link_libraries(XNWeightBalance PRIVATE ${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libC909_V1_Interface.so @@ -47,4 +57,7 @@ install(TARGETS XNWeightBalance file(GLOB CONFIG_FILE "*.mcfg") # 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) \ No newline at end of file +install(FILES ${CONFIG_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX} + RENAME "XNWeightBalance_V${MODEL_VERSION}.mcfg" +) \ No newline at end of file diff --git a/XNServices/XNUDPService/.vscode/settings.json b/XNServices/XNUDPService/.vscode/settings.json new file mode 100644 index 0000000..9b6b487 --- /dev/null +++ b/XNServices/XNUDPService/.vscode/settings.json @@ -0,0 +1,77 @@ +{ + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "span": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp" + } +} \ No newline at end of file diff --git a/XNServices/XNUDPService/CMakeLists.txt b/XNServices/XNUDPService/CMakeLists.txt index d90b5bb..9c645c2 100755 --- a/XNServices/XNUDPService/CMakeLists.txt +++ b/XNServices/XNUDPService/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(XNUDPService LANGUAGES CXX) +set(MODEL_VERSION "1.0.0.0") + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -22,6 +24,14 @@ add_library(XNUDPService SHARED XNUDPService_p.h ) +set_target_properties(XNUDPService PROPERTIES + LIBRARY_OUTPUT_NAME "libXNUDPService.so.${MODEL_VERSION}" + PREFIX "" + SUFFIX "" + SKIP_BUILD_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE +) + target_link_libraries(XNUDPService PRIVATE ${XNCore_PATH}/lib/libXNCore.so ) @@ -43,4 +53,7 @@ install(TARGETS XNUDPService file(GLOB CONFIG_FILE "*.scfg") # 使用 install 命令在安装时拷贝配置文件 -install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) \ No newline at end of file +install(FILES ${CONFIG_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX} + RENAME "XNUDPService_V${MODEL_VERSION}.mcfg" +) \ No newline at end of file diff --git a/XNServices/XNUDPService/XNUDPService.cpp b/XNServices/XNUDPService/XNUDPService.cpp index 2f5f7d6..ed97f0b 100755 --- a/XNServices/XNUDPService/XNUDPService.cpp +++ b/XNServices/XNUDPService/XNUDPService.cpp @@ -36,43 +36,68 @@ void XNUDPService::Initialize() { XNServiceObject::Initialize(); T_D(); - // 读取配置文件 - std::ifstream file(GetXmlPath()); - if (!file.is_open()) { - LOG_WARNING("无法打开配置文件:%s", GetXmlPath().c_str()); - return; - } - - std::stringstream buffer; - buffer << file.rdbuf(); - std::string content = buffer.str(); - file.close(); - - // 简单的XML解析 - size_t udpPos = content.find(""); - if (udpPos != std::string::npos) { - size_t localPortPos = content.find("", udpPos); - size_t targetHostPos = content.find("", udpPos); - size_t targetPortPos = content.find("", udpPos); - - if (localPortPos != std::string::npos) { - size_t endPos = content.find("", localPortPos); - d->localPort = std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11)); + if (d->_initialType == 0) { + // 读取配置文件 + std::ifstream file(GetXmlPath()); + if (!file.is_open()) { + LOG_WARNING("无法打开配置文件:%1,使用默认值", GetXmlPath().c_str()); + d->localPort = 12345; + d->targetHost = "127.0.0.1"; + d->targetPort = 54321; + return; } - if (targetHostPos != std::string::npos) { - size_t endPos = content.find("", targetHostPos); - d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12); - } - if (targetPortPos != std::string::npos) { - size_t endPos = content.find("", targetPortPos); - d->targetPort = - std::stoi(content.substr(targetPortPos + 12, endPos - targetPortPos - 12)); + + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + file.close(); + + // 简单的XML解析 + size_t udpPos = content.find(""); + if (udpPos != std::string::npos) { + size_t localPortPos = content.find("", udpPos); + size_t targetHostPos = content.find("", udpPos); + size_t targetPortPos = content.find("", udpPos); + + if (localPortPos != std::string::npos) { + size_t endPos = content.find("", localPortPos); + d->localPort = + std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11)); + } + if (targetHostPos != std::string::npos) { + size_t endPos = content.find("", targetHostPos); + d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12); + } + if (targetPortPos != std::string::npos) { + size_t endPos = content.find("", targetPortPos); + d->targetPort = + std::stoi(content.substr(targetPortPos + 12, endPos - targetPortPos - 12)); + } + } else { + LOG_WARNING("未找到UDP配置, 使用默认值"); + d->localPort = 12345; + d->targetHost = "127.0.0.1"; + d->targetPort = 54321; } } else { - LOG_WARNING("未找到UDP配置, 使用默认值"); - d->localPort = 12345; - d->targetHost = "127.0.0.1"; - d->targetPort = 54321; + try { + if (d->_otherParams.contains("LocalPort")) { + d->localPort = d->_otherParams["LocalPort"].get(); + } + if (d->_otherParams.contains("TargetHost")) { + d->targetHost = d->_otherParams["TargetHost"].get(); + } + if (d->_otherParams.contains("TargetPort")) { + d->targetPort = d->_otherParams["TargetPort"].get(); + } + LOG_INFO("UDP配置: 本地端口:%1, 目标主机:%2, 目标端口:%3", d->localPort, d->targetHost, + d->targetPort); + } catch (const std::exception &e) { + LOG_WARNING("解析JSON参数失败: %1, 使用默认值", e.what()); + d->localPort = 12345; + d->targetHost = "127.0.0.1"; + d->targetPort = 54321; + } } }