为XNSim添加了可以从数据库直接读取数据进行仿真的能力。现在同时支持数据库和配置文件两种模式

This commit is contained in:
jinchao 2025-05-27 15:16:11 +08:00
parent 7da7a8a5ee
commit 896b46a1b1
46 changed files with 1060 additions and 348 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scenario> <Scenario>
<Environment OSName="Debian" Version="11" RTXVersion="preempt-rt" CPUAffinity="0,1" WorkPath="/home/jin/MyCode/XNSim/Release/" ModelsPath="Models/" ServicesPath="Services/" DomainID="10"/> <Environment OSName="Debian" Version="11" RTXVersion="preempt-rt" CPUAffinity="0,1" PlaneName = "C909" WorkPath="/home/jin/MyCode/XNSim/Release/" ModelsPath="Models/" ServicesPath="Services/" DomainID="10"/>
<ConsoleOutput Debug="1" Info="1" Error="1" Warning="1"/> <ConsoleOutput Debug="1" Info="1" Error="1" Warning="1"/>
<Log Debug="0" Info="1" Error="1" Warning="1"/> <Log Debug="0" Info="1" Error="1" Warning="1"/>
<ModelGroup Name="本体模型组" Freq="120" Priority="99" CPUAff="0"> <ModelGroup Name="本体模型组" Freq="120" Priority="99" CPUAff="0">
<Model Name="ATA04气动模型" ClassName="XNAerodynamics"/> <Model Name="ATA04气动模型" ClassName="XNAerodynamics" Version="1.0.0.0"/>
<Model Name="ATA04地面操纵模型" ClassName="XNGroundHandling"/> <Model Name="ATA04地面操纵模型" ClassName="XNGroundHandling" Version="1.0.0.0"/>
<Model Name="ATA04质量模型" ClassName="XNWeightBalance"/> <Model Name="ATA04质量模型" ClassName="XNWeightBalance" Version="1.0.0.0"/>
<Model Name="ATA04数据处理模型" ClassName="XNATA04DataProcessor"/> <Model Name="ATA04数据处理模型" ClassName="XNATA04DataProcessor" Version="1.0.0.0"/>
</ModelGroup> </ModelGroup>
<ServicesList> <ServicesList>
<Service Name="UDP通信服务" ClassName="XNUDPService"/> <Service Name="UDP通信服务" ClassName="XNUDPService" Version="1.0.0.0"/>
</ServicesList> </ServicesList>
</Scenario> </Scenario>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Service>
<Name>XNUDPService</Name>
<Description>UDP通信服务</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-04 10:00:00</CreateTime>
<ChangeTime>2025-02-04 10:00:00</ChangeTime>
<CommandList>
<Command Name="TestCmd" Description="Test" Call="TestCall"/>
</CommandList>
<UDP>
<LocalPort>12345</LocalPort>
<TargetHost>127.0.0.1</TargetHost>
<TargetPort>54321</TargetPort>
</UDP>
</Service>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -40,6 +40,8 @@
# include <array> # include <array>
# include <cstring> # include <cstring>
# include <iostream> # include <iostream>
# include <sqlite3.h>
# include <nlohmann/json.hpp>
#endif #endif
#include <fastdds/dds/domain/DomainParticipant.hpp> #include <fastdds/dds/domain/DomainParticipant.hpp>
@ -53,6 +55,8 @@
#include <fastcdr/xcdr/optional.hpp> #include <fastcdr/xcdr/optional.hpp>
#define FAST_DDS_MACRO eprosima::fastdds::dds #define FAST_DDS_MACRO eprosima::fastdds::dds
using XN_JSON = nlohmann::json;
/** /**
* @brief Hz * @brief Hz
*/ */
@ -91,13 +95,6 @@ struct PERIOD_INFO {
*/ */
using XNTimePoint = std::chrono::system_clock::time_point; 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 * @brief
*/ */
@ -258,3 +255,37 @@ public:
public: \ public: \
using ThisType = cls; \ using ThisType = cls; \
using SuperType = sup; using SuperType = sup;
#define XN_UNUSED(x) (void)x
namespace XNSim
{
template <typename T>
constexpr typename std::underlying_type<T>::type enumValue(T e)
{
return static_cast<typename std::underlying_type<T>::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<std::string> 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<const char *>(sqlite3_column_text(stmt, column));
if (text == nullptr) {
return "";
}
return std::string(text);
}
} // namespace XNSim

View File

@ -77,4 +77,9 @@ struct XNFrameworkPrivate : public XNObjectPrivate {
* @brief XML * @brief XML
*/ */
std::string scenarioXml; std::string scenarioXml;
/**
* @brief ID
*/
uint32_t configId;
}; };

View File

@ -61,10 +61,14 @@ public:
* @brief * @brief
* @param modelPath: QString类型 * @param modelPath: QString类型
* @param className: QString类型 * @param className: QString类型
* @param modelVersion: QString类型
* @param initialType: UINT32类型
* @param threadID: UINT32类型线ID
* @details * @details
*/ */
void LoadModel(const std::string &modelPath, const std::string &className, uint32_t initialType, void LoadModel(const std::string &modelPath, const std::string &className,
uint32_t threadID); const std::string &modelVersion, const std::string &planeName,
uint32_t initialType, uint32_t threadID);
/** /**
* @brief * @brief

View File

@ -238,6 +238,10 @@ public:
public: public:
virtual void RegisterDDSParticipant(); virtual void RegisterDDSParticipant();
private:
void ParseXml();
void ParseConfig();
}; };
#define XN_MODEL_INITIALIZE(ClassName) \ #define XN_MODEL_INITIALIZE(ClassName) \

View File

@ -76,4 +76,21 @@ public:
* @return false: * @return false:
*/ */
virtual bool AnalysisScenarioXml(const std::string &XmlPath, uint32_t initialType); 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);
}; };

View File

@ -29,7 +29,7 @@ public:
virtual bool Initialize() override; virtual bool Initialize() override;
virtual bool PrepareForExecute() override; virtual bool PrepareForExecute() override;
void LoadService(const std::string &servicePath, const std::string &serviceName, void LoadService(const std::string &servicePath, const std::string &serviceName,
uint32_t initialType); const std::string &serviceVersion, uint32_t initialType);
public: public:
XNServiceObjectPtr GetService(uint32_t serviceID); XNServiceObjectPtr GetService(uint32_t serviceID);

View File

@ -54,6 +54,10 @@ public:
protected: protected:
XNFrameworkPtr GetFramework() const; XNFrameworkPtr GetFramework() const;
private:
void ParseXml();
void ParseConfig();
}; };
XNCLASS_PTR_DECLARE(XNServiceObject) XNCLASS_PTR_DECLARE(XNServiceObject)

View File

@ -11,4 +11,5 @@ struct XNServiceObjectPrivate : public XNObjectPrivate {
std::unordered_map<std::string, FAST_DDS_MACRO::DataWriter *> _dataWriters; std::unordered_map<std::string, FAST_DDS_MACRO::DataWriter *> _dataWriters;
XNFrameworkPtr pFramework; XNFrameworkPtr pFramework;
uint32_t _initialType; uint32_t _initialType;
XN_JSON _otherParams;
}; };

View File

@ -16,8 +16,10 @@ endif()
file(GLOB DDS_XNIDL_SOURCES_CXX "XNIDL/*.cxx") file(GLOB DDS_XNIDL_SOURCES_CXX "XNIDL/*.cxx")
find_package(nlohmann_json REQUIRED)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(SQLite3 REQUIRED)
add_library(XNCore SHARED add_library(XNCore SHARED
XNCore_global.h XNCore_global.h
@ -76,6 +78,7 @@ target_link_libraries(XNCore PRIVATE
pthread pthread
OpenSSL::SSL OpenSSL::SSL
OpenSSL::Crypto OpenSSL::Crypto
nlohmann_json
dl dl
) )

View File

@ -1,5 +1,7 @@
#include "XNCore_global.h" #include "XNCore_global.h"
namespace XNSim
{
XNTimePoint parseISOTime(const std::string &timeStr) XNTimePoint parseISOTime(const std::string &timeStr)
{ {
std::tm tm = {}; std::tm tm = {};
@ -8,3 +10,49 @@ XNTimePoint parseISOTime(const std::string &timeStr)
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm)); auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
return tp; return tp;
} }
// 辅助函数:分割字符串
std::vector<std::string> split(const std::string &str, const std::string &delim)
{
std::vector<std::string> 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

View File

@ -40,6 +40,8 @@
# include <array> # include <array>
# include <cstring> # include <cstring>
# include <iostream> # include <iostream>
# include <sqlite3.h>
# include <nlohmann/json.hpp>
#endif #endif
#include <fastdds/dds/domain/DomainParticipant.hpp> #include <fastdds/dds/domain/DomainParticipant.hpp>
@ -53,6 +55,8 @@
#include <fastcdr/xcdr/optional.hpp> #include <fastcdr/xcdr/optional.hpp>
#define FAST_DDS_MACRO eprosima::fastdds::dds #define FAST_DDS_MACRO eprosima::fastdds::dds
using XN_JSON = nlohmann::json;
/** /**
* @brief Hz * @brief Hz
*/ */
@ -91,13 +95,6 @@ struct PERIOD_INFO {
*/ */
using XNTimePoint = std::chrono::system_clock::time_point; 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 * @brief
*/ */
@ -258,3 +255,37 @@ public:
public: \ public: \
using ThisType = cls; \ using ThisType = cls; \
using SuperType = sup; using SuperType = sup;
#define XN_UNUSED(x) (void)x
namespace XNSim
{
template <typename T>
constexpr typename std::underlying_type<T>::type enumValue(T e)
{
return static_cast<typename std::underlying_type<T>::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<std::string> 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<const char *>(sqlite3_column_text(stmt, column));
if (text == nullptr) {
return "";
}
return std::string(text);
}
} // namespace XNSim

View File

@ -77,4 +77,9 @@ struct XNFrameworkPrivate : public XNObjectPrivate {
* @brief XML * @brief XML
*/ */
std::string scenarioXml; std::string scenarioXml;
/**
* @brief ID
*/
uint32_t configId;
}; };

View File

@ -55,6 +55,7 @@ bool XNModelManager::Initialize()
} }
void XNModelManager::LoadModel(const std::string &modelPath, const std::string &className, 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) uint32_t initialType, uint32_t threadID)
{ {
T_D(); T_D();
@ -77,10 +78,15 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string &
model->SetFramework(GetFramework()); model->SetFramework(GetFramework());
model->SetInitializeType(initialType); model->SetInitializeType(initialType);
model->SetThreadID(threadID); model->SetThreadID(threadID);
// 使用std::filesystem处理路径 if (initialType == 0) {
std::filesystem::path configPath = // 使用std::filesystem处理路径
std::filesystem::path(modelPath).parent_path() / (className + ".mcfg"); std::filesystem::path configPath =
model->SetXmlPath(configPath.string()); 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; d->ModelMap[modelID] = model;
@ -92,9 +98,10 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string &
if (threadID != 0) { if (threadID != 0) {
auto framework = GetFramework(); auto framework = GetFramework();
if (framework) { if (framework) {
framework->GetThreadManager()->RegisterFunction( // 注册到线程管理器 (重复注册了,暂删除)
modelID, std::bind(&XNModelObject::StepUpdate, model.get()), threadID, // framework->GetThreadManager()->RegisterFunction(
model->GetRunFreq(), model->GetRunNode(), model->GetRunPriority()); // modelID, std::bind(&XNModelObject::StepUpdate, model.get()), threadID,
// model->GetRunFreq(), model->GetRunNode(), model->GetRunPriority());
// 设置模型设置频率 // 设置模型设置频率
double threadFreq = double threadFreq =
framework->GetThreadManager()->GetThreadFreqByID(threadID); framework->GetThreadManager()->GetThreadFreqByID(threadID);

View File

@ -61,10 +61,14 @@ public:
* @brief * @brief
* @param modelPath: QString类型 * @param modelPath: QString类型
* @param className: QString类型 * @param className: QString类型
* @param modelVersion: QString类型
* @param initialType: UINT32类型
* @param threadID: UINT32类型线ID
* @details * @details
*/ */
void LoadModel(const std::string &modelPath, const std::string &className, uint32_t initialType, void LoadModel(const std::string &modelPath, const std::string &className,
uint32_t threadID); const std::string &modelVersion, const std::string &planeName,
uint32_t initialType, uint32_t threadID);
/** /**
* @brief * @brief

View File

@ -195,102 +195,210 @@ void XNModelObject::SetSetFreq(double setFreq)
// 初始化函数 // 初始化函数
void XNModelObject::Initialize() void XNModelObject::Initialize()
{ {
// 先尝试调取动态库
T_D(); T_D();
if (d->_initialType == 0) { if (d->_initialType == 0) {
// 读取配置文件,设置循环执行函数 ParseXml();
std::ifstream file(GetXmlPath()); } else {
if (!file.is_open()) { ParseConfig();
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();
// 使用标准C++时间处理 void XNModelObject::ParseXml()
std::string createTimeStr = rootNode->FirstChildElement("CreateTime")->GetText(); {
std::string changeTimeStr = rootNode->FirstChildElement("ChangeTime")->GetText(); T_D();
d->_cCreatTime = parseISOTime(createTimeStr); // 读取配置文件,设置循环执行函数
d->_cChangeTime = parseISOTime(changeTimeStr); 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(); // 使用标准C++时间处理
d->_runPriority = std::stoi(rootNode->FirstChildElement("Priority")->GetText()); 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" 形式 std::string funcNode = rootNode->FirstChildElement("Node")->GetText();
size_t tmp = funcNode.find('-'); d->_runPriority = XNSim::safe_stoi(rootNode->FirstChildElement("Priority")->GetText());
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;
}
// 使用标准C++字符串处理 // 检查运行节点是否是 "x-x" 形式
d->_runFreq = std::stoi(funcNode.substr(0, tmp)); size_t tmp = funcNode.find('-');
d->_runNode = std::stoi(funcNode.substr(tmp + 1)); 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;
}
// 注册周期性函数 // 使用标准C++字符串处理
auto framework = GetFramework(); d->_runFreq = XNSim::safe_stoi(funcNode.substr(0, tmp));
if (framework) { d->_runNode = XNSim::safe_stoi(funcNode.substr(tmp + 1));
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(); auto framework = GetFramework();
if (mathlib && strlen(mathlib) > 0) { if (framework) {
// 使用标准C++文件路径处理 auto threadManager = framework->GetThreadManager();
std::filesystem::path xmlPath(GetXmlPath()); if (threadManager) {
d->_sLibPath = xmlPath.parent_path().string() + "/" + mathlib; threadManager->RegisterFunction(
GetUniqueId(), std::bind(&XNModelObject::StepUpdate, this), d->_threadID,
// 使用标准C++动态库加载 d->_runFreq, d->_runNode, d->_runPriority);
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: 处理命令列表
}
} }
} }
// 加载动态库
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<std::string> 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);
} }
// 单步执行函数 // 单步执行函数

View File

@ -238,6 +238,10 @@ public:
public: public:
virtual void RegisterDDSParticipant(); virtual void RegisterDDSParticipant();
private:
void ParseXml();
void ParseConfig();
}; };
#define XN_MODEL_INITIALIZE(ClassName) \ #define XN_MODEL_INITIALIZE(ClassName) \

View File

@ -66,35 +66,19 @@ bool XNScenarioManager::PrepareForExecute()
return true; return true;
} }
// 辅助函数:分割字符串
std::vector<std::string> split(const std::string &str, const std::string &delim)
{
std::vector<std::string> 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) 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(); T_D();
std::ifstream file(XmlPath); 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 OSName = envInfo->Attribute("OSName");
std::string version = envInfo->Attribute("Version"); std::string version = envInfo->Attribute("Version");
std::string kernel = envInfo->Attribute("RTXVersion"); std::string kernel = envInfo->Attribute("RTXVersion");
std::string planeName = envInfo->Attribute("PlaneName");
// 设置工作目录 // 设置工作目录
std::string rootPath = envInfo->Attribute("WorkPath"); std::string rootPath = envInfo->Attribute("WorkPath");
GetFramework()->SetWorkPath(rootPath); GetFramework()->SetWorkPath(rootPath);
@ -128,7 +113,7 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t
GetFramework()->GetDDSManager()->SetDomainID(domainID); GetFramework()->GetDDSManager()->SetDomainID(domainID);
// 读取CPU亲和性 // 读取CPU亲和性
std::string cpuAff = envInfo->Attribute("CPUAffinity"); std::string cpuAff = envInfo->Attribute("CPUAffinity");
std::vector<std::string> cpuAffList = split(cpuAff, ","); std::vector<std::string> cpuAffList = XNSim::split(cpuAff, ",");
//读取服务列表 //读取服务列表
tinyxml2::XMLElement *serviceList = root->FirstChildElement("ServicesList"); tinyxml2::XMLElement *serviceList = root->FirstChildElement("ServicesList");
@ -137,10 +122,12 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t
while (service) { while (service) {
std::string serviceName = service->Attribute("Name"); std::string serviceName = service->Attribute("Name");
std::string libName = service->Attribute("ClassName"); std::string libName = service->Attribute("ClassName");
libName = getFileNameWithoutExt(libName); std::string serviceVersion = service->Attribute("Version");
std::string dynamicLibName = servicePath + "lib" + libName + ".so"; 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"); service = service->NextSiblingElement("Service");
} }
} }
@ -153,14 +140,14 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t
// 读取模型分组频率 // 读取模型分组频率
double modelGroupFreq = std::stod(modelGroup->Attribute("Freq")); 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) { if (modelGroupPriority > 99 || modelGroupPriority < 0) {
LOG_ERROR("0x2100 模型分组优先级设置错误,优先级值:%d", modelGroupPriority); LOG_ERROR("0x2100 模型分组优先级设置错误,优先级值:%d", modelGroupPriority);
return false; return false;
} }
// 读取模型分组CPU亲和性 // 读取模型分组CPU亲和性
std::string modelGroupCPUAff = modelGroup->Attribute("CPUAff"); std::string modelGroupCPUAff = modelGroup->Attribute("CPUAff");
std::vector<std::string> modelGroupCPUAffList = split(modelGroupCPUAff, ","); std::vector<std::string> modelGroupCPUAffList = XNSim::split(modelGroupCPUAff, ",");
// 验证CPU亲和性 // 验证CPU亲和性
for (const auto &cpu : modelGroupCPUAffList) { for (const auto &cpu : modelGroupCPUAffList) {
@ -188,10 +175,12 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t
while (model) { while (model) {
std::string modelName = model->Attribute("Name"); std::string modelName = model->Attribute("Name");
std::string libName = model->Attribute("ClassName"); std::string libName = model->Attribute("ClassName");
libName = getFileNameWithoutExt(libName); std::string modelVersion = model->Attribute("Version");
std::string dynamicLibName = modelPath + "lib" + libName + ".so"; 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"); model = model->NextSiblingElement("Model");
} }
@ -200,3 +189,204 @@ bool XNScenarioManager::AnalysisScenarioXml(const std::string &XmlPath, uint32_t
return true; 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<std::string> 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<std::string> 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;
}

View File

@ -76,4 +76,21 @@ public:
* @return false: * @return false:
*/ */
virtual bool AnalysisScenarioXml(const std::string &XmlPath, uint32_t initialType); 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);
}; };

View File

@ -38,7 +38,7 @@ bool XNServiceManager::PrepareForExecute()
} }
void XNServiceManager::LoadService(const std::string &servicePath, const std::string &serviceName, void XNServiceManager::LoadService(const std::string &servicePath, const std::string &serviceName,
uint32_t initialType) const std::string &serviceVersion, uint32_t initialType)
{ {
T_D(); T_D();
void *handle = dlopen(servicePath.c_str(), RTLD_LAZY); 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->SetUniqueId(serviceID);
service->SetObjectName(serviceName); service->SetObjectName(serviceName);
service->SetFramework(GetFramework()); service->SetFramework(GetFramework());
// 使用std::filesystem处理路径 if (initialType == 0) {
std::filesystem::path configPath = // 使用std::filesystem处理路径
std::filesystem::path(servicePath).parent_path() / (serviceName + ".scfg"); std::filesystem::path configPath =
service->SetXmlPath(configPath.string()); 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; d->ServiceList[serviceID] = service;
service->SetInitializeType(initialType); service->SetInitializeType(initialType);
// 初始化服务 // 初始化服务
LOG_INFO("0x2176 初始化服务: %1", serviceName);
service->Initialize(); service->Initialize();
} else { } else {
LOG_WARNING("0x2173 Service %s Not found in dynamic link library %s!", LOG_WARNING("0x2173 Service %s Not found in dynamic link library %s!",

View File

@ -29,7 +29,7 @@ public:
virtual bool Initialize() override; virtual bool Initialize() override;
virtual bool PrepareForExecute() override; virtual bool PrepareForExecute() override;
void LoadService(const std::string &servicePath, const std::string &serviceName, void LoadService(const std::string &servicePath, const std::string &serviceName,
uint32_t initialType); const std::string &serviceVersion, uint32_t initialType);
public: public:
XNServiceObjectPtr GetService(uint32_t serviceID); XNServiceObjectPtr GetService(uint32_t serviceID);

View File

@ -139,51 +139,154 @@ void XNServiceObject::Initialize()
{ {
T_D(); T_D();
if (d->_initialType == 0) { if (d->_initialType == 0) {
tinyxml2::XMLDocument doc; ParseXml();
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: 处理命令信息
}
}
} else { } 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<std::string> 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<std::string>());
// TODO: 处理服务命令信息
// d->_commandList.emplace_back(
// cmd["Name"].get<std::string>(),
// cmd["Description"].get<std::string>(),
// cmd["Call"].get<std::string>()
// );
}
}
}
} 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() void XNServiceObject::PrepareForExecute()
{ {
T_D(); T_D();

View File

@ -54,6 +54,10 @@ public:
protected: protected:
XNFrameworkPtr GetFramework() const; XNFrameworkPtr GetFramework() const;
private:
void ParseXml();
void ParseConfig();
}; };
XNCLASS_PTR_DECLARE(XNServiceObject) XNCLASS_PTR_DECLARE(XNServiceObject)

View File

@ -11,4 +11,5 @@ struct XNServiceObjectPrivate : public XNObjectPrivate {
std::unordered_map<std::string, FAST_DDS_MACRO::DataWriter *> _dataWriters; std::unordered_map<std::string, FAST_DDS_MACRO::DataWriter *> _dataWriters;
XNFrameworkPtr pFramework; XNFrameworkPtr pFramework;
uint32_t _initialType; uint32_t _initialType;
XN_JSON _otherParams;
}; };

View File

@ -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) { if (!framework) {
return false; return false;
} }
// 解析配置文件 if (InitializeType == 0) {
bool isReady = ParseConfig(XmlPath); // 解析配置文件
// 如果解析配置文件失败 bool isReady = ParseConfig(XmlPath);
if (!isReady) { // 如果解析配置文件失败
// 返回失败 if (!isReady) {
return false; // 返回失败
return false;
}
} else if (InitializeType == 1) {
// 解析数据库
bool isReady = ParseDataBase(XmlPath);
// 如果解析数据库失败
if (!isReady) {
// 返回失败
return false;
}
} }
// 设置场景XML路径 // 设置场景XML路径
framework->SetScenarioXml(XmlPath); framework->SetScenarioXml(XmlPath);
// 设置CPU亲和性 // 设置CPU亲和性
framework->SetCpuAffinity(CPUAffinity); framework->SetCpuAffinity(CPUAffinity);
// 单次触发初始化信号 // 单次触发初始化信号
bool ret = framework->Initialize(0); bool ret = framework->Initialize(InitializeType);
// 如果初始化失败 // 如果初始化失败
if (!ret) { if (!ret) {
LOG_ERROR("0x1012 初始化失败, 引擎将退出!"); 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"); std::string dbPath = std::getenv("XNCore");
@ -501,7 +512,7 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId)
// 打开数据库 // 打开数据库
sqlite3 *db; sqlite3 *db;
if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) { if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) {
LOG_ERROR("0x1016 打开数据库失败: {}", sqlite3_errmsg(db)); LOG_ERROR("0x1016 打开数据库失败: %1", sqlite3_errmsg(db));
return false; return false;
} }
@ -509,14 +520,15 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId)
std::string sql = "SELECT * FROM Configuration WHERE ConfID = ?"; std::string sql = "SELECT * FROM Configuration WHERE ConfID = ?";
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { 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); sqlite3_close(db);
return false; return false;
} }
// 绑定参数 // 绑定参数
if (sqlite3_bind_int(stmt, 1, ConfigId) != SQLITE_OK) { int configIdInt = std::stoi(ConfigId);
LOG_ERROR("0x1018 绑定参数失败: {}", sqlite3_errmsg(db)); if (sqlite3_bind_int(stmt, 1, configIdInt) != SQLITE_OK) {
LOG_ERROR("0x1018 绑定参数失败: %1", sqlite3_errmsg(db));
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
sqlite3_close(db); sqlite3_close(db);
return false; return false;
@ -524,7 +536,7 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId)
// 执行查询 // 执行查询
if (sqlite3_step(stmt) != SQLITE_ROW) { if (sqlite3_step(stmt) != SQLITE_ROW) {
LOG_ERROR("0x1019 未找到配置ID为{}的记录", ConfigId); LOG_ERROR("0x1019 未找到配置ID为%1的记录", ConfigId);
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
sqlite3_close(db); sqlite3_close(db);
return false; return false;
@ -539,7 +551,8 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId)
CPUAffinity = 0; CPUAffinity = 0;
// 读取配置信息 // 读取配置信息
std::string CPUAff = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 6)); std::string CPUAff = XNSim::getStringFromSqlite3(stmt, 6);
//std::string CPUAff = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 6));
std::istringstream iss(CPUAff); std::istringstream iss(CPUAff);
std::string cpuIndex; std::string cpuIndex;
@ -591,88 +604,6 @@ bool XNEngine::ParseDataBase(const uint32_t &ConfigId)
sqlite3_close(db); sqlite3_close(db);
return true; 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::XNRuntimeControlPubSubType>(
"XNSim::XNSimControl::XNRuntimeControl", 0, func);
// 触发仿真控制信号
framework->SimControl(0, SimControlCmd::Start);
// 注册引擎状态发布者
engineStatusWriter =
ddsManager->RegisterPublisher<XNSim::XNSimStatus::XNEngineStatusPubSubType>(
"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) void XNEngine::SetTestMode(bool isTestMode)
{ {

View File

@ -40,13 +40,8 @@ public:
* @param XmlPath XML路径 * @param XmlPath XML路径
* @return * @return
*/ */
bool Run(const std::string &XmlPath); bool Run(const std::string &XmlPath, const uint32_t InitializeType);
/**
* @brief
* @param ConfigId ID
* @return
*/
bool Run(const uint32_t &ConfigId);
/** /**
* @brief * @brief
* @param isTestMode * @param isTestMode
@ -66,7 +61,7 @@ private:
* @param ConfigId ID * @param ConfigId ID
* @return * @return
*/ */
bool ParseDataBase(const uint32_t &ConfigId); bool ParseDataBase(const std::string &ConfigId);
/** /**
* @brief * @brief

View File

@ -72,9 +72,9 @@ int main(int argc, char *argv[])
//检测配置文件格式 //检测配置文件格式
if (hasConfigPath) { if (hasConfigPath) {
return engine.Run(configPath); return engine.Run(configPath, 0);
} else if (hasConfigId) { } else if (hasConfigId) {
return engine.Run(configId); return engine.Run(configId, 1);
} }
return -1; return -1;
} }

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16)
project(XNATA04DataProcessor LANGUAGES CXX) project(XNATA04DataProcessor LANGUAGES CXX)
set(MODEL_VERSION "1.0.0.0")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -23,6 +25,14 @@ add_library(XNATA04DataProcessor SHARED
XNATA04DataProcessor_p.h 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 target_link_libraries(XNATA04DataProcessor PRIVATE
${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libXNCore.so
${XNCore_PATH}/lib/libC909_V1_Interface.so ${XNCore_PATH}/lib/libC909_V1_Interface.so
@ -45,4 +55,7 @@ install(TARGETS XNATA04DataProcessor
file(GLOB CONFIG_FILE "*.mcfg") file(GLOB CONFIG_FILE "*.mcfg")
# 使 install # 使 install
install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${CONFIG_FILE}
DESTINATION ${CMAKE_INSTALL_PREFIX}
RENAME "XNATA04DataProcessor_V${MODEL_VERSION}.mcfg"
)

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16)
project(XNAerodynamics LANGUAGES CXX) project(XNAerodynamics LANGUAGES CXX)
set(MODEL_VERSION "1.0.0.0")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@ -24,6 +26,14 @@ add_library(XNAerodynamics SHARED
XNAerodynamics_p.h 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 target_link_libraries(XNAerodynamics PRIVATE
${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libXNCore.so
${XNCore_PATH}/lib/libC909_V1_Interface.so ${XNCore_PATH}/lib/libC909_V1_Interface.so
@ -47,4 +57,7 @@ install(TARGETS XNAerodynamics
file(GLOB CONFIG_FILE "*.mcfg") file(GLOB CONFIG_FILE "*.mcfg")
# 使 install # 使 install
install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${CONFIG_FILE}
DESTINATION ${CMAKE_INSTALL_PREFIX}
RENAME "XNAerodynamics_V${MODEL_VERSION}.mcfg"
)

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16)
project(XNGroundHandling LANGUAGES CXX) project(XNGroundHandling LANGUAGES CXX)
set(MODEL_VERSION "1.0.0.0")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@ -24,6 +26,14 @@ add_library(XNGroundHandling SHARED
XNGroundHandling_p.h 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 target_link_libraries(XNGroundHandling PRIVATE
${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libXNCore.so
${XNCore_PATH}/lib/libC909_V1_Interface.so ${XNCore_PATH}/lib/libC909_V1_Interface.so
@ -46,4 +56,7 @@ install(TARGETS XNGroundHandling
file(GLOB CONFIG_FILE "*.mcfg") file(GLOB CONFIG_FILE "*.mcfg")
# 使 install # 使 install
install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${CONFIG_FILE}
DESTINATION ${CMAKE_INSTALL_PREFIX}
RENAME "XNGroundHandling_V${MODEL_VERSION}.mcfg"
)

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16)
project(XNWeightBalance LANGUAGES CXX) project(XNWeightBalance LANGUAGES CXX)
set(MODEL_VERSION "1.0.0.0")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@ -24,6 +26,14 @@ add_library(XNWeightBalance SHARED
XNWeightBalance_p.h 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 target_link_libraries(XNWeightBalance PRIVATE
${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libXNCore.so
${XNCore_PATH}/lib/libC909_V1_Interface.so ${XNCore_PATH}/lib/libC909_V1_Interface.so
@ -47,4 +57,7 @@ install(TARGETS XNWeightBalance
file(GLOB CONFIG_FILE "*.mcfg") file(GLOB CONFIG_FILE "*.mcfg")
# 使 install # 使 install
install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${CONFIG_FILE}
DESTINATION ${CMAKE_INSTALL_PREFIX}
RENAME "XNWeightBalance_V${MODEL_VERSION}.mcfg"
)

View File

@ -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"
}
}

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16)
project(XNUDPService LANGUAGES CXX) project(XNUDPService LANGUAGES CXX)
set(MODEL_VERSION "1.0.0.0")
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -22,6 +24,14 @@ add_library(XNUDPService SHARED
XNUDPService_p.h 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 target_link_libraries(XNUDPService PRIVATE
${XNCore_PATH}/lib/libXNCore.so ${XNCore_PATH}/lib/libXNCore.so
) )
@ -43,4 +53,7 @@ install(TARGETS XNUDPService
file(GLOB CONFIG_FILE "*.scfg") file(GLOB CONFIG_FILE "*.scfg")
# 使 install # 使 install
install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${CONFIG_FILE}
DESTINATION ${CMAKE_INSTALL_PREFIX}
RENAME "XNUDPService_V${MODEL_VERSION}.mcfg"
)

View File

@ -36,43 +36,68 @@ void XNUDPService::Initialize()
{ {
XNServiceObject::Initialize(); XNServiceObject::Initialize();
T_D(); T_D();
// 读取配置文件 if (d->_initialType == 0) {
std::ifstream file(GetXmlPath()); // 读取配置文件
if (!file.is_open()) { std::ifstream file(GetXmlPath());
LOG_WARNING("无法打开配置文件:%s", GetXmlPath().c_str()); if (!file.is_open()) {
return; LOG_WARNING("无法打开配置文件:%1使用默认值", GetXmlPath().c_str());
} d->localPort = 12345;
d->targetHost = "127.0.0.1";
std::stringstream buffer; d->targetPort = 54321;
buffer << file.rdbuf(); return;
std::string content = buffer.str();
file.close();
// 简单的XML解析
size_t udpPos = content.find("<UDP>");
if (udpPos != std::string::npos) {
size_t localPortPos = content.find("<LocalPort>", udpPos);
size_t targetHostPos = content.find("<TargetHost>", udpPos);
size_t targetPortPos = content.find("<TargetPort>", udpPos);
if (localPortPos != std::string::npos) {
size_t endPos = content.find("</LocalPort>", localPortPos);
d->localPort = std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11));
} }
if (targetHostPos != std::string::npos) {
size_t endPos = content.find("</TargetHost>", targetHostPos); std::stringstream buffer;
d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12); buffer << file.rdbuf();
} std::string content = buffer.str();
if (targetPortPos != std::string::npos) { file.close();
size_t endPos = content.find("</TargetPort>", targetPortPos);
d->targetPort = // 简单的XML解析
std::stoi(content.substr(targetPortPos + 12, endPos - targetPortPos - 12)); size_t udpPos = content.find("<UDP>");
if (udpPos != std::string::npos) {
size_t localPortPos = content.find("<LocalPort>", udpPos);
size_t targetHostPos = content.find("<TargetHost>", udpPos);
size_t targetPortPos = content.find("<TargetPort>", udpPos);
if (localPortPos != std::string::npos) {
size_t endPos = content.find("</LocalPort>", localPortPos);
d->localPort =
std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11));
}
if (targetHostPos != std::string::npos) {
size_t endPos = content.find("</TargetHost>", targetHostPos);
d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12);
}
if (targetPortPos != std::string::npos) {
size_t endPos = content.find("</TargetPort>", 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 { } else {
LOG_WARNING("未找到UDP配置, 使用默认值"); try {
d->localPort = 12345; if (d->_otherParams.contains("LocalPort")) {
d->targetHost = "127.0.0.1"; d->localPort = d->_otherParams["LocalPort"].get<int>();
d->targetPort = 54321; }
if (d->_otherParams.contains("TargetHost")) {
d->targetHost = d->_otherParams["TargetHost"].get<std::string>();
}
if (d->_otherParams.contains("TargetPort")) {
d->targetPort = d->_otherParams["TargetPort"].get<int>();
}
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;
}
} }
} }