/** * @file XNModelObject.cpp * @author jinchao * @brief 模型基类源文件 * @version 1.0 * @date 2024-11-07 * * @copyright Copyright (c) 2024 XN * */ #include "XNModelObject.h" #include "XNModelObject_p.h" #include "XNFramework.h" #include "XNThreadManager.h" #include "XNModelManager.h" #include "XNDDSManager.h" #include "XNIDL/XNSimStatusPubSubTypes.hpp" // 默认构造函数 XNModelObject::XNModelObject() : XNObject(new XNModelObjectPrivate()) { } // 默认析构函数 XNModelObject::~XNModelObject() { } XNModelObject::XNModelObject(PrivateType *p) : XNObject(p) { } void XNModelObject::SetFramework(XNFrameworkPtr framework) { T_D(); d->_framework = framework; } XNFrameworkPtr XNModelObject::GetFramework() const { T_D(); return d->_framework; } // 获取模型描述 const std::string &XNModelObject::GetDescription() { T_D(); return d->_sDescription; } // 设置模型描述 void XNModelObject::SetDescription(const std::string &sDescription) { T_D(); d->_sDescription = sDescription; } // 获取作者 const std::string &XNModelObject::GetAuthor() { T_D(); return d->_sAuthor; } // 设置作者 void XNModelObject::SetAuthor(const std::string &sAuthor) { T_D(); d->_sAuthor = sAuthor; } // 获取模型配置文件路径 const std::string &XNModelObject::GetXmlPath() { T_D(); return d->_sXmlPath; } // 设置模型配置文件路径 void XNModelObject::SetXmlPath(const std::string &sXmlPath) { T_D(); d->_sXmlPath = sXmlPath; } // 获取模型创建时间 const XNTimePoint &XNModelObject::GetCreateTime() { T_D(); return d->_cCreatTime; } // 设置模型创建时间 void XNModelObject::SetCreateTime(const XNTimePoint &cTime) { T_D(); d->_cCreatTime = cTime; } // 获取模型修改时间 const XNTimePoint &XNModelObject::GetChangeTime() { T_D(); return d->_cChangeTime; } // 设置模型修改时间 void XNModelObject::SetChangeTime(const XNTimePoint &cTime) { T_D(); d->_cChangeTime = cTime; } // 获取模型版本号 const std::string &XNModelObject::GetVersion() { T_D(); return d->_sVersion; } // 设置模型版本号 void XNModelObject::SetVersion(const std::string &sVersion) { T_D(); d->_sVersion = sVersion; } void XNModelObject::SetInitializeType(uint32_t initialType) { T_D(); d->_initialType = initialType; } void XNModelObject::SetThreadID(uint32_t threadID) { T_D(); d->_threadID = threadID; } uint32_t XNModelObject::GetThreadID() const { T_D(); return d->_threadID; } uint32_t XNModelObject::GetRunFreq() const { T_D(); return d->_runFreq; } void XNModelObject::SetRunFreq(uint32_t runFreq) { T_D(); d->_runFreq = runFreq; } uint32_t XNModelObject::GetRunNode() const { T_D(); return d->_runNode; } void XNModelObject::SetRunNode(uint32_t runNode) { T_D(); d->_runNode = runNode; } uint32_t XNModelObject::GetRunPriority() const { T_D(); return d->_runPriority; } void XNModelObject::SetRunPriority(uint32_t runPriority) { T_D(); d->_runPriority = runPriority; } double XNModelObject::GetSetFreq() const { T_D(); return d->_setFreq; } void XNModelObject::SetSetFreq(double setFreq) { T_D(); d->_setFreq = setFreq; } // 初始化函数 void XNModelObject::Initialize() { T_D(); if (d->_initialType == 0) { ParseXml(); } else { ParseConfig(); } } 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(); // 使用标准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); std::string funcNode = rootNode->FirstChildElement("Node")->GetText(); d->_runPriority = XNSim::safe_stoi(rootNode->FirstChildElement("Priority")->GetText()); // 检查运行节点是否是 "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; } // 使用标准C++字符串处理 d->_runFreq = XNSim::safe_stoi(funcNode.substr(0, tmp)); d->_runNode = XNSim::safe_stoi(funcNode.substr(tmp + 1)); // 注册周期性函数 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); } // 单步执行函数 void XNModelObject::StepUpdate() { T_D(); uint32_t setFreq = d->_setFreq < 1.0 ? 1 : (uint32_t)d->_setFreq; if (d->_dataWriter != nullptr && d->_runCnt > 0 && d->_runCnt % setFreq == 0) { XNSim::XNSimStatus::XNModelStatus modelStatus; modelStatus.XNModelName(GetObjectName()); modelStatus.XNModelID(GetUniqueId()); modelStatus.XNModelSt(1); modelStatus.XNModelThID(d->_threadID); modelStatus.XNModelNode(d->_runNode); modelStatus.XNModelPro(d->_runPriority); modelStatus.XNModelRunCnt(d->_runCnt); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); double time_diff = (now.tv_sec - d->_lastRunTime.tv_sec) + (now.tv_nsec - d->_lastRunTime.tv_nsec) / 1.0E9; modelStatus.XNMdlCurFreq(d->_setFreq / time_diff); modelStatus.XNMdlSetFreq(d->_setFreq); d->_dataWriter->write(&modelStatus); d->_lastRunTime = now; LOG_DEBUG("Model: %1 Write DDS!", GetObjectName()); } d->_runCnt++; } // 运行前最后准备函数 void XNModelObject::PrepareForExecute() { T_D(); d->_runCnt = 0; // 注册DDS RegisterDDSParticipant(); clock_gettime(CLOCK_MONOTONIC, &d->_lastRunTime); } void XNModelObject::RegisterDDSParticipant() { T_D(); auto framework = GetFramework(); if (framework == nullptr) { LOG_WARNING("Failed to get Framework!"); return; } auto ddsManager = framework->GetDDSManager(); if (ddsManager == nullptr) { LOG_WARNING("Failed to get DDSManager!"); return; } uint32_t MyID = GetUniqueId(); d->_dataWriter = ddsManager->RegisterPublisher( "XNSim::XNSimStatus::XNModelStatus", MyID); } int XNModelObject::RegisterEventHandler(const std::string &eventName, XNEventCallback callback, bool async, XNEvent::Priority priority) { // 获取事件管理器 auto framework = GetFramework(); if (framework == nullptr) { LOG_WARNING("Failed to get Framework!"); return -1; } XNEventManagerPtr eventManager = framework->GetEventManager(); if (eventManager == nullptr) { LOG_WARNING("Failed to get EventManager!"); return -1; } // 注册事件处理器 return eventManager->RegisterEventHandler(eventName, callback, GetUniqueId(), async, priority); } void XNModelObject::TriggerEvent(const std::string &eventName, const std::any &eventData, bool forceAsync, XNEvent::Priority priority) { // 获取事件管理器 auto framework = GetFramework(); if (framework == nullptr) { LOG_WARNING("Failed to get Framework!"); return; } XNEventManagerPtr eventManager = framework->GetEventManager(); if (eventManager == nullptr) { LOG_WARNING("Failed to get EventManager!"); return; } // 触发事件 eventManager->TriggerEvent(eventName, eventData, forceAsync, priority); }