diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1.zip b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1.zip new file mode 100644 index 0000000..98e157f Binary files /dev/null and b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1.zip differ diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/CMakeLists.txt b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/CMakeLists.txt new file mode 100644 index 0000000..ea7764f --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.16) + +project(XNGroundHandling LANGUAGES CXX) + +set(MODEL_VERSION "2.0.143.1") + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +if(DEFINED ENV{XNCore}) + set(XNCore_PATH $ENV{XNCore}) +else() + message(FATAL_ERROR "Environment variable XNCore is not set.") +endif() + +include_directories(${XNCore_PATH}/include) +include_directories(${XNCore_PATH}/IDL) + +add_library(XNGroundHandling SHARED + XNGroundHandling_global.h + XNGroundHandling.cpp + XNGroundHandling.h + XNGroundHandling_p.h +) + +set_target_properties(XNGroundHandling PROPERTIES + LIBRARY_OUTPUT_NAME "libXNGroundHandling.so.2.0.143.1" + 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 + dl +) + +target_compile_definitions(XNGroundHandling PRIVATE XNGROUNDHANDLING_LIBRARY) + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Configuration/C909_V1/Models" CACHE PATH "Install path prefix" FORCE) +endif() + +install(TARGETS XNGroundHandling BUNDLE DESTINATION . LIBRARY DESTINATION . RUNTIME DESTINATION .) + +file(GLOB CONFIG_FILE "*.mcfg") + +install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX} RENAME "${CMAKE_PROJECT_NAME}_V${MODEL_VERSION}.mcfg") + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.cpp b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.cpp new file mode 100644 index 0000000..0d9acb2 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.cpp @@ -0,0 +1,319 @@ +#include "XNGroundHandling.h" +#include "XNGroundHandling_p.h" +#include + +XN_MODEL_INITIALIZE(XNGroundHandling) + +XNGroundHandling::XNGroundHandling() : XNModelObject(new XNGroundHandlingPrivate()) +{ +} + +XNGroundHandling::~XNGroundHandling() +{ +} + +XNGroundHandling::XNGroundHandling(PrivateType *p) : XNModelObject(p) +{ +} + +void XNGroundHandling::Initialize() +{ + T_D(); + SuperType::Initialize(); + if (d->_dynamicLib) { + d->_fun = (FunctionType)dlsym(d->_dynamicLib, d->_entryPointName.c_str()); + if (!d->_fun) { + LOG_WARNING( + "Failed to resolve _Z29SACSCGroundHandlingEntryPointP20ComacDataStructure_S"); + } + } + /* 在这里进行其它初始化 */ +} + +void XNGroundHandling::PrepareForExecute() +{ + T_D(); + SuperType::PrepareForExecute(); + InitializeData(); + d->_inputInterface.Initialize(GetFramework(), GetUniqueId(), 1); + d->_outputInterface.Initialize(GetFramework(), GetUniqueId(), 2); + d->_heartbeatInterface.Initialize(GetFramework(), GetUniqueId(), 2); + /* 在这里进行其它运行前准备工作 */ +} + +void XNGroundHandling::StepUpdate() +{ + T_D(); + SuperType::StepUpdate(); + if (d->_fun) { + d->_inputInterface.getData(d->_data.input_ground); + d->_fun(&d->_data); + d->_outputInterface.setData(d->_data.output_ground); + d->_heartbeatInterface.setData(&d->_data); + } + /* 在这里进行其它运行时计算 */ +} + +void XNGroundHandling::InitializeData() +{ + T_D(); + d->_data.input_ground = new input_ground_S; + // TODO: 在这里初始化输入数据 + d->_data.input_ground->l_04_i_gdcomac_brake_torq_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.input_ground->l_04_i_gdcomac_brake_torq_f8[i] = new double[2]; + } + d->_data.input_ground->l_04_i_gdcomac_gear_f8 = new double[3]; + d->_data.input_ground->l_04_i_gdcomac_gsteer_f8 = new double[3]; + d->_data.input_ground->l_04_i_gdcomac_tire_pres_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.input_ground->l_04_i_gdcomac_tire_pres_f8[i] = new double[2]; + } + d->_data.input_ground->l_04_i_gdcomac_contdep_f8 = new double[7]; + d->_data.input_ground->l_04_i_gdcomac_brake_temp_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.input_ground->l_04_i_gdcomac_brake_temp_f8[i] = new double[2]; + } + d->_data.input_ground->l_04_i_gdcomac_tire_tburst_l1 = new unsigned char *[3]; + for (int i = 0; i < 3; i++) { + d->_data.input_ground->l_04_i_gdcomac_tire_tburst_l1[i] = new unsigned char[2]; + } + d->_data.input_ground->l_04_i_gdcomac_tire_tflat_l1 = new unsigned char *[3]; + for (int i = 0; i < 3; i++) { + d->_data.input_ground->l_04_i_gdcomac_tire_tflat_l1[i] = new unsigned char[2]; + } + d->_data.input_ground->l_04_i_gdcomac_rcon_ci_f8 = new double[14]; + + d->_data.output_ground = new output_ground_S; + // TODO: 在这里初始化输出数据 + d->_data.output_ground->l_04_o_gdcomac_fygs_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_mzgs_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_mu_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_dstroke_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_sr_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_sr_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_sy_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_sy_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_sx_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_sx_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_xft_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_yft_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_zft_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_tire_vel_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_tire_vel_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_tire_temp_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_tire_temp_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_tire_burst_l1 = new unsigned char *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_tire_burst_l1[i] = new unsigned char[2]; + } + d->_data.output_ground->l_04_o_gdcomac_utirew_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_utirew_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_vtirew_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_vtirew_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_whl_omega_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_whl_omega_f8[i] = new double[2]; + } + d->_data.output_ground->l_04_o_gdcomac_dstruc_f8 = new double[6]; + d->_data.output_ground->l_04_o_gdcomac_nd_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_wor_par_f8 = new double[3]; + d->_data.output_ground->l_04_o_gdcomac_vczt_f8 = new double *[3]; + for (int i = 0; i < 3; i++) { + d->_data.output_ground->l_04_o_gdcomac_vczt_f8[i] = new double[2]; + } + d->_data.groundhandling_model_heartbeat = 0; +} + +void XNGroundHandling::ReleaseData() +{ + T_D(); + // TODO: 在这里释放输入数据 + + if (d->_data.input_ground) { + if (d->_data.input_ground->l_04_i_gdcomac_brake_torq_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.input_ground->l_04_i_gdcomac_brake_torq_f8[i]) { + delete[] d->_data.input_ground->l_04_i_gdcomac_brake_torq_f8[i]; + } + } + delete[] d->_data.input_ground->l_04_i_gdcomac_brake_torq_f8; + } + if (d->_data.input_ground->l_04_i_gdcomac_gear_f8) { + delete[] d->_data.input_ground->l_04_i_gdcomac_gear_f8; + } + if (d->_data.input_ground->l_04_i_gdcomac_gsteer_f8) { + delete[] d->_data.input_ground->l_04_i_gdcomac_gsteer_f8; + } + if (d->_data.input_ground->l_04_i_gdcomac_tire_pres_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.input_ground->l_04_i_gdcomac_tire_pres_f8[i]) { + delete[] d->_data.input_ground->l_04_i_gdcomac_tire_pres_f8[i]; + } + } + delete[] d->_data.input_ground->l_04_i_gdcomac_tire_pres_f8; + } + if (d->_data.input_ground->l_04_i_gdcomac_contdep_f8) { + delete[] d->_data.input_ground->l_04_i_gdcomac_contdep_f8; + } + if (d->_data.input_ground->l_04_i_gdcomac_brake_temp_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.input_ground->l_04_i_gdcomac_brake_temp_f8[i]) { + delete[] d->_data.input_ground->l_04_i_gdcomac_brake_temp_f8[i]; + } + } + delete[] d->_data.input_ground->l_04_i_gdcomac_brake_temp_f8; + } + if (d->_data.input_ground->l_04_i_gdcomac_tire_tburst_l1) { + for (int i = 0; i < 3; i++) { + if (d->_data.input_ground->l_04_i_gdcomac_tire_tburst_l1[i]) { + delete[] d->_data.input_ground->l_04_i_gdcomac_tire_tburst_l1[i]; + } + } + delete[] d->_data.input_ground->l_04_i_gdcomac_tire_tburst_l1; + } + if (d->_data.input_ground->l_04_i_gdcomac_tire_tflat_l1) { + for (int i = 0; i < 3; i++) { + if (d->_data.input_ground->l_04_i_gdcomac_tire_tflat_l1[i]) { + delete[] d->_data.input_ground->l_04_i_gdcomac_tire_tflat_l1[i]; + } + } + delete[] d->_data.input_ground->l_04_i_gdcomac_tire_tflat_l1; + } + if (d->_data.input_ground->l_04_i_gdcomac_rcon_ci_f8) { + delete[] d->_data.input_ground->l_04_i_gdcomac_rcon_ci_f8; + } + delete d->_data.input_ground; + d->_data.input_ground = nullptr; + } + // TODO: 在这里释放输出数据 + + if (d->_data.output_ground) { + if (d->_data.output_ground->l_04_o_gdcomac_fygs_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_fygs_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_mzgs_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_mzgs_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_mu_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_mu_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_dstroke_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_dstroke_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_sr_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_sr_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_sr_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_sr_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_sy_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_sy_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_sy_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_sy_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_sx_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_sx_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_sx_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_sx_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_xft_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_xft_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_yft_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_yft_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_zft_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_zft_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_tire_vel_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_tire_vel_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_tire_vel_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_tire_vel_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_tire_temp_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_tire_temp_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_tire_temp_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_tire_temp_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_tire_burst_l1) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_tire_burst_l1[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_tire_burst_l1[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_tire_burst_l1; + } + if (d->_data.output_ground->l_04_o_gdcomac_utirew_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_utirew_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_utirew_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_utirew_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_vtirew_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_vtirew_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_vtirew_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_vtirew_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_whl_omega_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_whl_omega_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_whl_omega_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_whl_omega_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_dstruc_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_dstruc_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_nd_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_nd_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_wor_par_f8) { + delete[] d->_data.output_ground->l_04_o_gdcomac_wor_par_f8; + } + if (d->_data.output_ground->l_04_o_gdcomac_vczt_f8) { + for (int i = 0; i < 3; i++) { + if (d->_data.output_ground->l_04_o_gdcomac_vczt_f8[i]) { + delete[] d->_data.output_ground->l_04_o_gdcomac_vczt_f8[i]; + } + } + delete[] d->_data.output_ground->l_04_o_gdcomac_vczt_f8; + } + delete d->_data.output_ground; + d->_data.output_ground = nullptr; + } +} diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.h b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.h new file mode 100644 index 0000000..dc35fbe --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.h @@ -0,0 +1,30 @@ +#pragma once + +#include "XNGroundHandling_global.h" +#include + +struct XNGroundHandlingPrivate; + +class XNGROUNDHANDLING_EXPORT XNGroundHandling : public XNModelObject +{ +XN_METATYPE(XNGroundHandling, XNModelObject) +XN_DECLARE_PRIVATE(XNGroundHandling) +public: + XNGroundHandling(); + virtual ~XNGroundHandling(); + +protected: + XNGroundHandling(PrivateType *p); + +public: + virtual void Initialize() override; + virtual void PrepareForExecute() override; + virtual void StepUpdate() override; + +protected: + void InitializeData(); + void ReleaseData(); +}; + +XNCLASS_PTR_DECLARE(XNGroundHandling) + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.mcfg b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.mcfg new file mode 100644 index 0000000..dafd5d7 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling.mcfg @@ -0,0 +1,13 @@ + + + XNGroundHandling + ATA04GroundHandling + Jin + 2.0.143.1 + 2025-04-03 14:47:42 + 2025-04-03 14:47:42 + 0 + 99 + ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H + + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling_global.h b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling_global.h new file mode 100644 index 0000000..e989176 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling_global.h @@ -0,0 +1,11 @@ +#ifndef XNGROUNDHANDLING_GLOBAL_H +#define XNGROUNDHANDLING_GLOBAL_H + +#if defined(XNGROUNDHANDLING_LIBRARY) +#define XNGROUNDHANDLING_EXPORT __attribute__((visibility("default"))) +#else +#define XNGROUNDHANDLING_EXPORT __attribute__((visibility("default"))) +#endif + +#endif // XNGROUNDHANDLING_GLOBAL_H + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling_p.h b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling_p.h new file mode 100644 index 0000000..7d4d0e5 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNGroundHandling_2.0.143.1/XNGroundHandling_p.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../../Packages/ATA04_SACSCGroundHandling_2.0.143.1H_20250506/std_04_dll.h" +#include "../../IDL/C909_V1_Interface.h" + +using InterfaceType = ComacDataStructure_S; +typedef void (*FunctionType)(InterfaceType *); + +struct XNGroundHandlingPrivate : public XNModelObjectPrivate{ + FunctionType _fun = nullptr; + InterfaceType _data; + std::string _entryPointName = "_Z29SACSCGroundHandlingEntryPointP20ComacDataStructure_S"; + std::mutex _mutex; + XNSim::C909::ATA04::GroundHandling_input_Interface _inputInterface; + XNSim::C909::ATA04::GroundHandling_output_Interface _outputInterface; + XNSim::C909::ATA04::GroundHandling_heartbeat_Interface _heartbeatInterface; +}; + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6.zip b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6.zip new file mode 100644 index 0000000..fb3925e Binary files /dev/null and b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6.zip differ diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/CMakeLists.txt b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/CMakeLists.txt new file mode 100644 index 0000000..cd9ff57 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.16) + +project(XNWeightBalance LANGUAGES CXX) + +set(MODEL_VERSION "2.0.14.6") + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +if(DEFINED ENV{XNCore}) + set(XNCore_PATH $ENV{XNCore}) +else() + message(FATAL_ERROR "Environment variable XNCore is not set.") +endif() + +include_directories(${XNCore_PATH}/include) +include_directories(${XNCore_PATH}/IDL) + +add_library(XNWeightBalance SHARED + XNWeightBalance_global.h + XNWeightBalance.cpp + XNWeightBalance.h + XNWeightBalance_p.h +) + +set_target_properties(XNWeightBalance PROPERTIES + LIBRARY_OUTPUT_NAME "libXNWeightBalance.so.2.0.14.6" + 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 + dl +) + +target_compile_definitions(XNWeightBalance PRIVATE XNWEIGHTBALANCE_LIBRARY) + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Configuration/C909_V1/Models" CACHE PATH "Install path prefix" FORCE) +endif() + +install(TARGETS XNWeightBalance BUNDLE DESTINATION . LIBRARY DESTINATION . RUNTIME DESTINATION .) + +file(GLOB CONFIG_FILE "*.mcfg") + +install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX} RENAME "${CMAKE_PROJECT_NAME}_V${MODEL_VERSION}.mcfg") + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.cpp b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.cpp new file mode 100644 index 0000000..4b098e4 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.cpp @@ -0,0 +1,106 @@ +#include "XNWeightBalance.h" +#include "XNWeightBalance_p.h" +#include + +XN_MODEL_INITIALIZE(XNWeightBalance) + +XNWeightBalance::XNWeightBalance() : XNModelObject(new XNWeightBalancePrivate()) +{ +} + +XNWeightBalance::~XNWeightBalance() +{ +} + +XNWeightBalance::XNWeightBalance(PrivateType *p) : XNModelObject(p) +{ +} + +void XNWeightBalance::Initialize() +{ + T_D(); + SuperType::Initialize(); + if (d->_dynamicLib) { + d->_fun = (FunctionType)dlsym(d->_dynamicLib, d->_entryPointName.c_str()); + if (!d->_fun) { + LOG_WARNING( + "Failed to resolve _Z28SACSCWeightBalanceEntryPointP20ComacDataStructure_S"); + } + } + /* 在这里进行其它初始化 */ +} + +void XNWeightBalance::PrepareForExecute() +{ + T_D(); + SuperType::PrepareForExecute(); + InitializeData(); + d->_inputInterface.Initialize(GetFramework(), GetUniqueId(), 1); + d->_outputInterface.Initialize(GetFramework(), GetUniqueId(), 2); + d->_heartbeatInterface.Initialize(GetFramework(), GetUniqueId(), 2); + /* 在这里进行其它运行前准备工作 */ +} + +void XNWeightBalance::StepUpdate() +{ + T_D(); + SuperType::StepUpdate(); + if (d->_fun) { + d->_inputInterface.getData(d->_data.input_weight); + d->_fun(&d->_data); + d->_outputInterface.setData(d->_data.output_weight); + d->_heartbeatInterface.setData(&d->_data); + } + /* 在这里进行其它运行时计算 */ +} + +void XNWeightBalance::InitializeData() +{ + T_D(); + d->_data.input_weight = new input_weight_S; + // TODO: 在这里初始化输入数据 + d->_data.input_weight->l_04_i_wbcomac_acset_tankfuel_f4 = new float[20]; + d->_data.input_weight->l_04_i_wbcomac_eng_efsep_l1 = new unsigned char[4]; + d->_data.input_weight->l_04_i_wbcomac_fuel_f8 = new double[20]; + d->_data.input_weight->l_04_i_wbcomac_kice_f8 = new double[20]; + + d->_data.output_weight = new output_weight_S; + // TODO: 在这里初始化输出数据 + d->_data.output_weight->l_04_o_wbcomac_fuel_cmd_f8 = new double[20]; + d->_data.output_weight->l_04_o_wbcomac_ice_eng_f8 = new double[4]; + + d->_data.weightbody_model_heartbeat = 0; +} + +void XNWeightBalance::ReleaseData() +{ + T_D(); + if (d->_data.input_weight) { + // TODO: 在这里释放输入数据 + if (d->_data.input_weight->l_04_i_wbcomac_acset_tankfuel_f4) { + delete[] d->_data.input_weight->l_04_i_wbcomac_acset_tankfuel_f4; + } + if (d->_data.input_weight->l_04_i_wbcomac_eng_efsep_l1) { + delete[] d->_data.input_weight->l_04_i_wbcomac_eng_efsep_l1; + } + if (d->_data.input_weight->l_04_i_wbcomac_fuel_f8) { + delete[] d->_data.input_weight->l_04_i_wbcomac_fuel_f8; + } + if (d->_data.input_weight->l_04_i_wbcomac_kice_f8) { + delete[] d->_data.input_weight->l_04_i_wbcomac_kice_f8; + } + delete d->_data.input_weight; + d->_data.input_weight = nullptr; + } + if (d->_data.output_weight) { + // TODO: 在这里释放输出数据 + if (d->_data.output_weight->l_04_o_wbcomac_fuel_cmd_f8) { + delete[] d->_data.output_weight->l_04_o_wbcomac_fuel_cmd_f8; + } + if (d->_data.output_weight->l_04_o_wbcomac_ice_eng_f8) { + delete[] d->_data.output_weight->l_04_o_wbcomac_ice_eng_f8; + } + delete d->_data.output_weight; + d->_data.output_weight = nullptr; + } +} diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.h b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.h new file mode 100644 index 0000000..be3a712 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.h @@ -0,0 +1,30 @@ +#pragma once + +#include "XNWeightBalance_global.h" +#include + +struct XNWeightBalancePrivate; + +class XNWEIGHTBALANCE_EXPORT XNWeightBalance : public XNModelObject +{ +XN_METATYPE(XNWeightBalance, XNModelObject) +XN_DECLARE_PRIVATE(XNWeightBalance) +public: + XNWeightBalance(); + virtual ~XNWeightBalance(); + +protected: + XNWeightBalance(PrivateType *p); + +public: + virtual void Initialize() override; + virtual void PrepareForExecute() override; + virtual void StepUpdate() override; + +protected: + void InitializeData(); + void ReleaseData(); +}; + +XNCLASS_PTR_DECLARE(XNWeightBalance) + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.mcfg b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.mcfg new file mode 100644 index 0000000..99abe38 --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance.mcfg @@ -0,0 +1,13 @@ + + + XNWeightBalance + ATA04WeightBalance + Jin + 2.0.14.6 + 2025-04-27 13:57:50 + 2025-04-27 13:57:50 + 0 + 99 + ATA04_WeightBalance_2.0.14.6H_20241106/libSACSCWeightBalance.so + + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance_global.h b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance_global.h new file mode 100644 index 0000000..84583ae --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance_global.h @@ -0,0 +1,11 @@ +#ifndef XNWEIGHTBALANCE_GLOBAL_H +#define XNWEIGHTBALANCE_GLOBAL_H + +#if defined(XNWEIGHTBALANCE_LIBRARY) +#define XNWEIGHTBALANCE_EXPORT __attribute__((visibility("default"))) +#else +#define XNWEIGHTBALANCE_EXPORT __attribute__((visibility("default"))) +#endif + +#endif // XNWEIGHTBALANCE_GLOBAL_H + diff --git a/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance_p.h b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance_p.h new file mode 100644 index 0000000..67b7fcb --- /dev/null +++ b/Release/Configuration/C909_V1/ModelProjects/XNWeightBalance_2.0.14.6/XNWeightBalance_p.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../../Packages/ATA04_WeightBalance_2.0.14.6H_20241106/std_04_dll.h" +#include "../../IDL/C909_V1_Interface.h" + +using InterfaceType = ComacDataStructure_S; +typedef void (*FunctionType)(InterfaceType *); + +struct XNWeightBalancePrivate : public XNModelObjectPrivate{ + FunctionType _fun = nullptr; + InterfaceType _data; + std::string _entryPointName = "_Z28SACSCWeightBalanceEntryPointP20ComacDataStructure_S"; + std::mutex _mutex; + XNSim::C909::ATA04::WeightBalance_input_Interface _inputInterface; + XNSim::C909::ATA04::WeightBalance_output_Interface _outputInterface; + XNSim::C909::ATA04::WeightBalance_heartbeat_Interface _heartbeatInterface; +}; + diff --git a/Release/Configuration/C909_V1/Models/XNGroundHandling_V1.0.0.0.mcfg b/Release/Configuration/C909_V1/Models/XNGroundHandling_V1.0.0.0.mcfg deleted file mode 100644 index 99fb1a1..0000000 --- a/Release/Configuration/C909_V1/Models/XNGroundHandling_V1.0.0.0.mcfg +++ /dev/null @@ -1,13 +0,0 @@ - - - XNGroundHandling - ATA04地面操纵模型 - Jin - 1.0.0 - 2025-02-19 16:22:17 - 2025-02-19 16:22:19 - 0-0 - 99 - ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H - - diff --git a/Release/Configuration/C909_V1/Models/XNGroundHandling_V2.0.143.1.mcfg b/Release/Configuration/C909_V1/Models/XNGroundHandling_V2.0.143.1.mcfg index 99fb1a1..dafd5d7 100644 --- a/Release/Configuration/C909_V1/Models/XNGroundHandling_V2.0.143.1.mcfg +++ b/Release/Configuration/C909_V1/Models/XNGroundHandling_V2.0.143.1.mcfg @@ -1,13 +1,13 @@ - XNGroundHandling - ATA04地面操纵模型 - Jin - 1.0.0 - 2025-02-19 16:22:17 - 2025-02-19 16:22:19 - 0-0 - 99 - ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H - + XNGroundHandling + ATA04GroundHandling + Jin + 2.0.143.1 + 2025-04-03 14:47:42 + 2025-04-03 14:47:42 + 0 + 99 + ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H + diff --git a/Release/Configuration/C909_V1/Models/XNWeightBalance_V1.0.0.0.mcfg b/Release/Configuration/C909_V1/Models/XNWeightBalance_V1.0.0.0.mcfg deleted file mode 100644 index 85e8ac9..0000000 --- a/Release/Configuration/C909_V1/Models/XNWeightBalance_V1.0.0.0.mcfg +++ /dev/null @@ -1,13 +0,0 @@ - - - XNWeightBalance - ATA04质量模型 - Jin - 1.0.0 - 2025-02-20 09:29:18 - 2025-02-20 09:29:20 - 0-0 - 99 - ATA04_WeightBalance_2.0.14.6H_20241106/libSACSCWeightBalance.so - - diff --git a/Release/Configuration/C909_V1/Models/XNWeightBalance_V2.0.14.6.mcfg b/Release/Configuration/C909_V1/Models/XNWeightBalance_V2.0.14.6.mcfg new file mode 100644 index 0000000..99abe38 --- /dev/null +++ b/Release/Configuration/C909_V1/Models/XNWeightBalance_V2.0.14.6.mcfg @@ -0,0 +1,13 @@ + + + XNWeightBalance + ATA04WeightBalance + Jin + 2.0.14.6 + 2025-04-27 13:57:50 + 2025-04-27 13:57:50 + 0 + 99 + ATA04_WeightBalance_2.0.14.6H_20241106/libSACSCWeightBalance.so + + diff --git a/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.1.0.0.0 b/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.1.0.0.0 deleted file mode 100644 index 5d62bba..0000000 Binary files a/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.1.0.0.0 and /dev/null differ diff --git a/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.2.0.143.1 b/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.2.0.143.1 index 2704ceb..93e1cd9 100644 Binary files a/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.2.0.143.1 and b/Release/Configuration/C909_V1/Models/libXNGroundHandling.so.2.0.143.1 differ diff --git a/Release/Configuration/C909_V1/Models/libXNWeightBalance.so.1.0.0.0 b/Release/Configuration/C909_V1/Models/libXNWeightBalance.so.1.0.0.0 deleted file mode 100644 index 0395e4f..0000000 Binary files a/Release/Configuration/C909_V1/Models/libXNWeightBalance.so.1.0.0.0 and /dev/null differ diff --git a/Release/Configuration/C909_V1/Models/libXNWeightBalance.so.2.0.14.6 b/Release/Configuration/C909_V1/Models/libXNWeightBalance.so.2.0.14.6 new file mode 100644 index 0000000..be5c9c2 Binary files /dev/null and b/Release/Configuration/C909_V1/Models/libXNWeightBalance.so.2.0.14.6 differ diff --git a/Release/Configuration/C909_V1/PluginCode/C909_V1_plugin.cpp b/Release/Configuration/C909_V1/PluginCode/C909_V1_plugin.cpp new file mode 100644 index 0000000..3a2fd50 --- /dev/null +++ b/Release/Configuration/C909_V1/PluginCode/C909_V1_plugin.cpp @@ -0,0 +1,84 @@ +#include +#include +// C909_V1接口头文件 - 只在插件中包含 +#include "../IDL/C909_V1_Interface.h" + +// 插件信息 +static PluginInfo plugin_info = {"C909_V1", "", DATAMONITOR_PLUGIN_INTERFACE_VERSION}; + +// 支持的接口列表 +static const char *supported_interfaces[] = { + "Aerodynamics_input", + "GroundHandling_input", + "GroundHandling_output", + "Aerodynamics_output", + "WeightBalance_input", + "WeightBalance_output", + "GroundHandling_heartbeat", + "WeightBalance_heartbeat", + "Aerodynamics_heartbeat" +}; + +static const int interface_count = sizeof(supported_interfaces) / sizeof(supported_interfaces[0]); + +// 导出的插件函数 +extern "C" +{ + + PluginInfo *get_plugin_info() + { + return &plugin_info; + } + + DataMonitorBasePtr create_monitor(const char *interfaceName) + { + std::string name(interfaceName); + + if (name == "Aerodynamics_input") { + return std::make_shared>(); + } else + if (name == "GroundHandling_input") { + return std::make_shared>(); + } else + if (name == "GroundHandling_output") { + return std::make_shared>(); + } else + if (name == "Aerodynamics_output") { + return std::make_shared>(); + } else + if (name == "WeightBalance_input") { + return std::make_shared>(); + } else + if (name == "WeightBalance_output") { + return std::make_shared>(); + } else + if (name == "GroundHandling_heartbeat") { + return std::make_shared>(); + } else + if (name == "WeightBalance_heartbeat") { + return std::make_shared>(); + } else + if (name == "Aerodynamics_heartbeat") { + return std::make_shared>(); + } + return nullptr; + } + + void destroy_monitor(const char *interfaceName) + { + // 智能指针会自动管理内存,这里可以添加额外的清理逻辑 + } + + const char **get_supported_interfaces(int *count) + { + if (count) { + *count = interface_count; + } + return const_cast(supported_interfaces); + } + + void free_string_array(const char **array) + { + // 这里不需要释放,因为使用的是静态数组 + } +} diff --git a/Release/Configuration/C909_V1/PluginCode/CMakeLists.txt b/Release/Configuration/C909_V1/PluginCode/CMakeLists.txt new file mode 100644 index 0000000..420e4d9 --- /dev/null +++ b/Release/Configuration/C909_V1/PluginCode/CMakeLists.txt @@ -0,0 +1,44 @@ +# CMakeLists.txt for C909_V1_Monitor plugin +cmake_minimum_required(VERSION 3.10) + +# 设置项目名称 +project(C909_V1_Monitor_plugin) + +# 设置C++标准 +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 查找必要的包 +find_package(PkgConfig REQUIRED) +find_package(FastDDS REQUIRED) +if(DEFINED ENV{XNCore}) + set(XNCore_PATH $ENV{XNCore}) +else() + message(FATAL_ERROR "Environment variable XNCore is not set.") +endif() +include_directories(${XNCore_PATH}/include) +# 创建插件库 +add_library(C909_V1_Monitor SHARED + C909_V1_plugin.cpp +) + +# 链接库 +target_link_libraries(C909_V1_Monitor + fastcdr + fastdds + OpenSSL::SSL + OpenSSL::Crypto + ${XNCore_PATH}/lib/libC909_V1_Interface.so + ${XNCore_PATH}/lib/libXNMonitorServer.so +) + +target_compile_definitions(C909_V1_Monitor PRIVATE C909_V1_Monitor_LIBRARY) +if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Configuration/C909_V1/Plugins" CACHE PATH "Install path prefix" FORCE) +endif() +include(GNUInstallDirs) +install(TARGETS C909_V1_Monitor + BUNDLE DESTINATION . + LIBRARY DESTINATION . + RUNTIME DESTINATION . +) diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index d1135b3..bff1153 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/Release/include/XNMonitor/CSVDataInjectThread.h b/Release/include/XNMonitor/CSVDataInjectThread.h new file mode 100644 index 0000000..8299d1e --- /dev/null +++ b/Release/include/XNMonitor/CSVDataInjectThread.h @@ -0,0 +1,66 @@ +#pragma once + +#include "DataMonitor.h" + +/** + * @brief 数据注入线程类,用于持续向数据监控器注入数据 + */ +class CSVDataInjectThread +{ +public: + /** + * @brief 构造函数 + * @param csvFilePath CSV文件路径 + */ + CSVDataInjectThread(std::string csvFilePath); + + /** + * @brief 析构函数 + */ + ~CSVDataInjectThread(); + + bool Initialize(std::vector injectDataInfos); + + /** + * @brief 启动数据注入线程 + */ + void start(); + + /** + * @brief 停止数据注入线程 + */ + void stop(); + + /** + * @brief 从CSV文件读取下一行数据并更新执行时间 + * 如果文件读取完毕,将停止线程 + */ + void updateData(); + + bool isRunning() const; + +private: + /** + * @brief 线程执行函数 + */ + void threadFunc(); + + void parseHeaderField(const std::string &headerField); + +private: + std::string m_csvFilePath; + std::ifstream m_csvFile; + std::vector m_injectDataInfos; + std::vector m_headerFields; + std::thread m_thread; ///< 数据注入线程 + std::atomic m_running; ///< 线程运行标志 + std::mutex m_mutex; ///< 互斥锁 + std::condition_variable m_cv; ///< 条件变量 + std::unordered_map + m_alreadyStartedMonitors; ///< 已经启动的数据监控器 + std::unordered_map + m_notStartedMonitors; ///< 未启动的数据监控器 + std::unordered_map> + m_data; ///< 要注入的数据 + std::atomic m_nextExecuteTime; ///< 下一次执行的时间点 +}; \ No newline at end of file diff --git a/Release/include/XNMonitor/DataCollect.h b/Release/include/XNMonitor/DataCollect.h new file mode 100644 index 0000000..4fcae71 --- /dev/null +++ b/Release/include/XNMonitor/DataCollect.h @@ -0,0 +1,52 @@ +#pragma once + +#include "DataMonitor.h" + +class DataCollect +{ +public: + DataCollect(); + ~DataCollect(); + +public: + bool Initialize(std::vector collectDataInfos, std::string dcsFilePath); + + void start(); + + void stop(); + + /** + * @brief 从CSV文件读取下一行数据并更新执行时间 + * 如果文件读取完毕,将停止线程 + */ + void updateData(); + + bool isRunning() const; + +private: + /** + * @brief 线程执行函数 + */ + void threadFunc(); + + void parseHeaderField(const std::string &headerField); + +private: + std::string m_outputFileName; + std::ofstream m_outputFile; + std::vector m_collectDataInfos; + std::vector m_headerFields; + std::thread m_thread; ///< 数据采集线程 + std::atomic m_running; ///< 线程运行标志 + std::mutex m_mutex; ///< 互斥锁 + std::condition_variable m_cv; ///< 条件变量 + std::unordered_map + m_alreadyStartedMonitors; ///< 已经启动的数据监控器 + std::unordered_map + m_notStartedMonitors; ///< 未启动的数据监控器 + std::unordered_map> + m_data; ///< 采集到的数据 + std::atomic m_nextExecuteTime; ///< 下一次执行的时间点 + int m_collectDuration; ///< 采集时长(秒) + int m_collectFrequency; ///< 采集频率(Hz) +}; \ No newline at end of file diff --git a/Release/include/XNMonitor/DataInjectThread.h b/Release/include/XNMonitor/DataInjectThread.h new file mode 100644 index 0000000..1e55fec --- /dev/null +++ b/Release/include/XNMonitor/DataInjectThread.h @@ -0,0 +1,63 @@ +#pragma once + +#include "DataMonitor.h" + +/** + * @brief 数据注入线程类,用于持续向数据监控器注入数据 + */ +class DataInjectThread +{ +public: + /** + * @brief 构造函数 + * @param dataMonitor 数据监控器指针 + * @param data 要注入的数据 + * @param frequency 注入频率(Hz) + */ + DataInjectThread(DataMonitorBasePtr dataMonitor, + std::unordered_map data, double frequency); + + /** + * @brief 析构函数 + */ + ~DataInjectThread(); + + /** + * @brief 启动数据注入线程 + */ + void start(); + + /** + * @brief 停止数据注入线程 + */ + void stop(); + + /** + * @brief 更新要注入的数据 + * @param data 新的数据 + */ + void updateData(const std::unordered_map &data); + + /** + * @brief 更新注入频率 + * @param frequency 新的频率(Hz) + */ + void updateFrequency(double frequency); + +private: + /** + * @brief 线程执行函数 + */ + void threadFunc(); + +private: + std::thread m_thread; ///< 数据注入线程 + std::atomic m_running; ///< 线程运行标志 + std::mutex m_mutex; ///< 互斥锁 + std::condition_variable m_cv; ///< 条件变量 + DataMonitorBasePtr m_dataMonitor; ///< 数据监控器指针 + std::unordered_map m_data; ///< 要注入的数据 + std::atomic m_frequency; ///< 注入频率 +}; + +using DataInjectThreadPtr = std::shared_ptr; \ No newline at end of file diff --git a/Release/include/XNMonitor/DataMonitor.h b/Release/include/XNMonitor/DataMonitor.h new file mode 100644 index 0000000..68d82bb --- /dev/null +++ b/Release/include/XNMonitor/DataMonitor.h @@ -0,0 +1,80 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "TypeDefine.h" +#include "TopicManager.h" + +#define THISUNUSED(x) (void)(x) + +class XNFramework; +using XNFrameworkPtr = std::shared_ptr; + +class XNMONITORSERVER_EXPORT DataMonitorBase +{ +public: + virtual void Initialize(XNFrameworkPtr framework, uint32_t modelId, uint32_t DDS_type) = 0; + virtual std::unordered_map + getStringData(std::vector varNames) = 0; + virtual void setDataByString(std::unordered_map data) = 0; + virtual bool isInitialized() { return _isInitialized; } + +protected: + bool _isInitialized = false; +}; + +template +class XNMONITORSERVER_EXPORT DataMonitorProduct : public T, public DataMonitorBase +{ +public: + DataMonitorProduct() : T() {}; + virtual ~DataMonitorProduct() + { + try { + if (auto topicManager = TopicManager::Instance()) { + topicManager->unregisterSubscriber(T::topic_name); + topicManager->unregisterPublisher(T::topic_name); + } + } catch (...) { + return; + } + _isInitialized = false; + }; + + virtual void Initialize(XNFrameworkPtr framework, uint32_t modelId, uint32_t DDS_type) override + { + THISUNUSED(framework); + THISUNUSED(modelId); + THISUNUSED(DDS_type); + XNDDSErrorCode ret = + TopicManager::Instance()->registerSubscriber( + T::topic_name, + std::bind(&DataMonitorProduct::inputDataListener, this, std::placeholders::_1)); + if (ret != XNDDSErrorCode::SUCCESS) { + return; + } + ret = TopicManager::Instance()->registerPublisher( + T::topic_name, this->dataWriter); + if (ret != XNDDSErrorCode::SUCCESS || this->dataWriter == nullptr) { + return; + } + _isInitialized = true; + }; + + virtual std::unordered_map + getStringData(std::vector varNames) override + { + if (!isInitialized()) { + return {}; + } + return T::getStringData(varNames); + } + virtual void setDataByString(std::unordered_map data) override + { + if (!isInitialized()) { + return; + } + T::setDataByString(data); + } +}; + +using DataMonitorBasePtr = std::shared_ptr; diff --git a/Release/include/XNMonitor/DataMonitorFactory.h b/Release/include/XNMonitor/DataMonitorFactory.h new file mode 100644 index 0000000..a981523 --- /dev/null +++ b/Release/include/XNMonitor/DataMonitorFactory.h @@ -0,0 +1,25 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "DataMonitor.h" + +/** + * @brief DataMonitor工厂类,用于创建不同类型的DataMonitor实例 + */ +class XNMONITORSERVER_EXPORT DataMonitorFactory +{ +public: + static DataMonitorBasePtr GetInstance(const std::string &interfaceName); + + static void ReleaseInstance(const std::string &interfaceName); + + // 检查接口是否存在 + static bool HasInterface(const std::string &interfaceName); + + // 获取所有已注册的接口名称 + static std::vector GetRegisteredInterfaces(); + +private: + DataMonitorFactory() = delete; + ~DataMonitorFactory() = delete; +}; diff --git a/Release/include/XNMonitor/ModelInfoMonitor.h b/Release/include/XNMonitor/ModelInfoMonitor.h new file mode 100644 index 0000000..7c9a4fb --- /dev/null +++ b/Release/include/XNMonitor/ModelInfoMonitor.h @@ -0,0 +1,37 @@ +#pragma once + +#include "TopicManager.h" +#include + +class XNMONITORSERVER_EXPORT ModelInfoMonitor +{ +public: + explicit ModelInfoMonitor() {} + virtual ~ModelInfoMonitor(); + +public: + std::string Initialize(); + + std::string GetAllModelInfo(); + +private: + /** + * @brief 模型状态监听 + * @param status 模型状态 + */ + void ModelStatusListener(const XNSim::XNSimStatus::XNModelStatus &status); + +private: + /** + * @brief 互斥锁 + */ + std::mutex m_ModelStatusMutex; + /** + * @brief 模型状态 + */ + std::map m_ModelStatus; + /** + * @brief 模型周期计数 + */ + std::map m_ModelCycleCount; +}; diff --git a/Release/include/XNMonitor/PluginGenerator.h b/Release/include/XNMonitor/PluginGenerator.h new file mode 100644 index 0000000..e2ed0ce --- /dev/null +++ b/Release/include/XNMonitor/PluginGenerator.h @@ -0,0 +1,66 @@ +/** + * @file PluginGenerator.h + * @brief 简化的插件生成器 - 从数据库生成插件cpp文件和CMakeLists + */ + +#pragma once +#include "TypeDefine.h" + +// 接口信息结构 +struct InterfaceInfo { + std::string interfaceName; // 接口名称(如:Aerodynamics_heartbeat) + std::string + templateType; // 模板类型(如:XNSim::C909::ATA04::Aerodynamics_heartbeat_Interface) +}; + +// 插件信息 +struct GenPluginInfo { + std::string pluginName; // 插件名称(如:C909_V1) + std::string pluginDescription; // 插件描述 + std::string interfaceHeaderPath; // 接口头文件路径(如:IDL/C909_V1_Interface.h) + std::vector interfaces; // 接口列表 + std::string outputDirectory; // 输出目录 +}; + +class PluginGenerator +{ +public: + PluginGenerator(); + ~PluginGenerator(); + + // 从数据库加载插件信息 + bool loadPluginFromDatabase(const int confID); + + // 生成插件cpp文件 + bool generatePluginCpp(); + + // 生成CMakeLists.txt + bool generateCMakeLists(); + + // 编译插件 + bool compilePlugin(); + + // 获取错误信息 + std::string getLastError() const; + + // 获取插件信息 + const GenPluginInfo &getPluginInfo() const; + +private: + // 生成插件cpp文件内容 + std::string generatePluginCppContent(); + + // 生成CMakeLists.txt内容 + std::string generateCMakeListsContent(); + + // 写入文件 + bool writeFile(const std::string &filePath, const std::string &content); + + // 创建目录 + bool createDirectory(const std::string &dirPath); + +private: + std::string m_lastError; + + GenPluginInfo m_pluginInfo; +}; diff --git a/Release/include/XNMonitor/PluginInterface.h b/Release/include/XNMonitor/PluginInterface.h new file mode 100644 index 0000000..c5c10ed --- /dev/null +++ b/Release/include/XNMonitor/PluginInterface.h @@ -0,0 +1,34 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "DataMonitor.h" +#include "TypeDefine.h" + +// 插件信息结构 +struct PluginInfo { + const char *name; // 插件名称,如 "C909_V1" + const char *description; // 描述信息 + const char *interface_version; // 接口版本,必须与主项目兼容 +}; + +// C风格插件接口 - 确保ABI兼容性 +extern "C" +{ + // 获取插件信息 + typedef PluginInfo *(*GetPluginInfoFunc)(); + + // 创建监控器实例 + typedef DataMonitorBasePtr (*CreateMonitorFunc)(const char *interfaceName); + + // 销毁监控器实例 + typedef void (*DestroyMonitorFunc)(const char *interfaceName); + + // 获取支持的接口列表 + typedef const char **(*GetSupportedInterfacesFunc)(int *count); + + // 释放字符串数组 + typedef void (*FreeStringArrayFunc)(const char **array); +} + +// 插件接口版本 - 主项目一旦发布就不再修改 +#define DATAMONITOR_PLUGIN_INTERFACE_VERSION "1.0.0" \ No newline at end of file diff --git a/Release/include/XNMonitor/PluginManager.h b/Release/include/XNMonitor/PluginManager.h new file mode 100644 index 0000000..7f8bbf3 --- /dev/null +++ b/Release/include/XNMonitor/PluginManager.h @@ -0,0 +1,51 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "PluginInterface.h" +#include "PluginGenerator.h" +#include "TypeDefine.h" + +class XNMONITORSERVER_EXPORT PluginManager +{ +public: + static PluginManager &Instance(); + + // 设置生成的插件信息 + void SetGeneratedPluginInfo(const GenPluginInfo &pluginInfo); + + // 从生成器加载插件 + bool LoadPluginFromGenerator(); + + // 卸载当前插件 + void UnloadCurrentPlugin(); + + // 获取监控器实例 + DataMonitorBasePtr GetMonitor(const std::string &interfaceName); + + // 获取所有支持的接口 + std::vector GetSupportedInterfaces(); + + // 检查插件是否已加载 + bool IsPluginLoaded() const; + +private: + PluginManager() = default; + ~PluginManager(); + PluginManager(const PluginManager &) = delete; + PluginManager &operator=(const PluginManager &) = delete; + + // 当前加载的插件信息 + void *m_pluginHandle = nullptr; + PluginInfo *m_pluginInfo = nullptr; + GetPluginInfoFunc m_getPluginInfoFunc = nullptr; + CreateMonitorFunc m_createMonitorFunc = nullptr; + DestroyMonitorFunc m_destroyMonitorFunc = nullptr; + GetSupportedInterfacesFunc m_getSupportedInterfacesFunc = nullptr; + FreeStringArrayFunc m_freeStringArrayFunc = nullptr; + + // 生成的插件信息 + GenPluginInfo m_generatedPluginInfo; + + // 监控器实例缓存 + std::unordered_map m_monitorCache; +}; \ No newline at end of file diff --git a/Release/include/XNMonitor/SystemControl.h b/Release/include/XNMonitor/SystemControl.h new file mode 100644 index 0000000..3f4b176 --- /dev/null +++ b/Release/include/XNMonitor/SystemControl.h @@ -0,0 +1,24 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "TypeDefine.h" +#include "TopicManager.h" +#include + +class XNMONITORSERVER_EXPORT SystemControl +{ +public: + SystemControl() {}; + virtual ~SystemControl(); + +public: + std::string Initialize(); + void Pause(); + void Resume(); + void Stop(); + + void cleanup(); + +private: + XNDataWriter *m_EngineControlWriter; +}; diff --git a/Release/include/XNMonitor/SystemInfoMonitor.h b/Release/include/XNMonitor/SystemInfoMonitor.h new file mode 100644 index 0000000..defa515 --- /dev/null +++ b/Release/include/XNMonitor/SystemInfoMonitor.h @@ -0,0 +1,52 @@ +#pragma once + +#include "TopicManager.h" +#include + +class XNMONITORSERVER_EXPORT SystemInfoMonitor +{ +public: + explicit SystemInfoMonitor() {} + virtual ~SystemInfoMonitor(); + +public: + std::string Initialize(); + + std::string GetSystemInfo(); + std::string GetAllThreadInfo(); + +private: + /** + * @brief 引擎状态监听器 + * @param status 引擎状态 + */ + void EngineStatusListener(const XNSim::XNSimStatus::XNEngineStatus &status); + /** + * @brief 线程状态监听器 + * @param status 线程状态 + */ + void ThreadStatusListener(const XNSim::XNSimStatus::XNThreadStatus &status); + +private: + /** + * @brief 互斥锁 + */ + std::mutex m_EngineStatusMutex; + std::mutex m_ThreadStatusMutex; + /** + * @brief 引擎状态 + */ + XNSim::XNSimStatus::XNEngineStatus m_EngineStatus; + /** + * @brief 引擎状态更新 + */ + bool m_EngineStatusUpdate = false; + /** + * @brief 线程状态 + */ + std::map m_ThreadStatus; + /** + * @brief 线程周期计数 + */ + std::map m_ThreadCycleCount; +}; diff --git a/Release/include/XNMonitor/TopicManager.h b/Release/include/XNMonitor/TopicManager.h new file mode 100644 index 0000000..3e3cf81 --- /dev/null +++ b/Release/include/XNMonitor/TopicManager.h @@ -0,0 +1,310 @@ +/** + * @file TopicManager.h + * @author jinchao + * @brief 主题管理类 + * @version 1.0 + * @date 2025-03-10 + * + * @copyright Copyright (c) 2025 COMAC + * + */ +#pragma once + +#include "XNMonitorServer_global.h" +#include "XNDataReaderListenerImpl.h" + +/** + * @brief 主题管理类 + */ +class TopicManager +{ +public: + /** + * @brief 删除拷贝构造 + */ + TopicManager(const TopicManager &) = delete; + /** + * @brief 删除赋值操作 + */ + TopicManager &operator=(const TopicManager &) = delete; + + /** + * @brief 获取单例 + * @return TopicManager*: 主题管理类实例 + */ + static TopicManager *Instance() + { + if (instance == nullptr) { + std::lock_guard locker(instanceMutex); + if (instance == nullptr) { // 双重检查锁定 + instance = new TopicManager(); + } + } + return instance; + } + + /** + * @brief 清理参与者 + */ + static void cleanupParticipant() + { + std::lock_guard locker(instanceMutex); + if (instance != nullptr) { + instance->clearAllTopic(); // 清理所有主题 + if (instance->m_Participant != nullptr) { + eprosima::fastdds::dds::DomainParticipantFactory::get_instance() + ->delete_participant(instance->m_Participant); // 删除参与者 + instance->m_Participant = nullptr; // 设置参与者为空 + } + } + } + +private: + /** + * @brief 显式构造函数 + */ + explicit TopicManager() {} + + /** + * @brief 析构函数 + */ + virtual ~TopicManager() {} + +public: + /** + * @brief 初始化参与者 + * @param domainId: 域ID + */ + XNDDSErrorCode initializeParticipant(int domainId) + { + XNParticipantQos participantQos = eprosima::fastdds::dds::PARTICIPANT_QOS_DEFAULT; + participantQos.name("XNMonitor"); // 设置参与者名称 + m_Participant = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->create_participant( + domainId, participantQos); // 创建参与者 + if (m_Participant == nullptr) { + return XNDDSErrorCode::INIT_FAILED; + } + return XNDDSErrorCode::SUCCESS; + }; + + /** + * @brief 注册发布者模板函数 + * @tparam T: 类型 + * @param topicName: 主题名称 + * @return XNDataWriter*: 数据写入器 + */ + template + XNDDSErrorCode registerPublisher(const std::string &topicName, XNDataWriter *&dataWriter) + { + std::lock_guard locker(m_Mutex); + if (topics_.find(topicName) == topics_.end()) { + topics_[topicName] = MonitorTopicInfo(); // 创建主题信息 + MonitorTopicInfo &tmp = topics_[topicName]; // 获取主题信息 + XNTypeSupport typeSupport(new T()); // 创建类型支持 + typeSupport.register_type(m_Participant); // 注册类型 + tmp.topic = + m_Participant->create_topic(topicName.c_str(), typeSupport.get_type_name(), + eprosima::fastdds::dds::TOPIC_QOS_DEFAULT); // 创建主题 + if (tmp.topic == nullptr) { + topics_.erase(topicName); // 移除主题 + return XNDDSErrorCode::TOPIC_CREATE_FAILED; + } + } + MonitorTopicInfo &topicInfo = topics_[topicName]; // 获取主题信息 + if (topicInfo.publisher == nullptr) { + topicInfo.publisher = m_Participant->create_publisher( + eprosima::fastdds::dds::PUBLISHER_QOS_DEFAULT); // 创建发布者 + if (topicInfo.publisher == nullptr) { + return XNDDSErrorCode::PUBLISHER_CREATE_FAILED; + } + } + + if (topicInfo.dataWriter == nullptr) { + XNDataWriterQos dataWriterQos; + // 设置数据写入器的持久性策略, 使用瞬态本地持久性 + dataWriterQos.durability().kind = eprosima::fastdds::dds::VOLATILE_DURABILITY_QOS; + // 设置数据写入器的生命周期策略, 设置为5秒 + dataWriterQos.lifespan().duration = eprosima::fastdds::dds::Duration_t(5, 0); + topicInfo.dataWriter = topicInfo.publisher->create_datawriter( + topicInfo.topic, dataWriterQos); // 创建数据写入器 + if (topicInfo.dataWriter == nullptr) { + return XNDDSErrorCode::DATAWRITER_CREATE_FAILED; + } + } + dataWriter = topicInfo.dataWriter; + return XNDDSErrorCode::SUCCESS; + } + + /** + * @brief 注销发布者 + * @param topicName: 主题名称 + */ + void unregisterPublisher(const std::string &topicName) + { + std::lock_guard locker(m_Mutex); + unregisterPublisherWithoutLock(topicName); + } + + /** + * @brief 注销发布者, 不带锁 + * @param topicName: 主题名称 + */ + void unregisterPublisherWithoutLock(const std::string &topicName) + { + auto it = topics_.find(topicName); + if (it != topics_.end()) { + MonitorTopicInfo &topicInfo = it->second; // 获取主题信息 + if (topicInfo.dataWriter != nullptr) { + topicInfo.publisher->delete_datawriter(topicInfo.dataWriter); // 删除数据写入器 + topicInfo.dataWriter = nullptr; // 设置数据写入器为空 + } + if (topicInfo.publisher != nullptr) { + m_Participant->delete_publisher(topicInfo.publisher); // 删除发布者 + topicInfo.publisher = nullptr; // 设置发布者为空 + } + if (topicInfo.publisher == nullptr && topicInfo.subscriber == nullptr + && topicInfo.topic != nullptr) { + m_Participant->delete_topic(topicInfo.topic); // 删除主题 + topicInfo.topic = nullptr; // 设置主题为空 + topics_.erase(it); // 移除主题 + } + } + } + + /** + * @brief 注册订阅者模板函数 + * @tparam T: 类型 + * @param topicName: 主题名称 + * @param fun: 回调函数 + */ + template + XNDDSErrorCode registerSubscriber(const std::string &topicName, + std::function fun) + { + std::lock_guard locker(m_Mutex); + if (topics_.find(topicName) == topics_.end()) { + topics_[topicName] = MonitorTopicInfo(); // 创建主题信息 + MonitorTopicInfo &tmp = topics_[topicName]; // 获取主题信息 + XNTypeSupport typeSupport(new T()); // 创建类型支持 + typeSupport.register_type(m_Participant); // 注册类型 + tmp.topic = + m_Participant->create_topic(topicName.c_str(), typeSupport.get_type_name(), + eprosima::fastdds::dds::TOPIC_QOS_DEFAULT); // 创建主题 + if (tmp.topic == nullptr) { + topics_.erase(topicName); // 移除主题 + return XNDDSErrorCode::TOPIC_CREATE_FAILED; // 返回 + } + } + MonitorTopicInfo &topicInfo = topics_[topicName]; // 获取主题信息 + if (topicInfo.subscriber == nullptr) { + topicInfo.subscriber = m_Participant->create_subscriber( + eprosima::fastdds::dds::SUBSCRIBER_QOS_DEFAULT); // 创建订阅者 + if (topicInfo.subscriber == nullptr) { + return XNDDSErrorCode::SUBSCRIBER_CREATE_FAILED; // 返回 + } + } + if (topicInfo.dataReader == nullptr) { + XNDataReaderQos dataReaderQos; + dataReaderQos.durability().kind = + eprosima::fastdds::dds::VOLATILE_DURABILITY_QOS; // 设置数据读取器的持久性策略 + topicInfo.listener = + new XNDataReaderListenerImpl(fun); // 创建数据读取器监听器 + topicInfo.dataReader = topicInfo.subscriber->create_datareader( + topicInfo.topic, dataReaderQos, topicInfo.listener); // 创建数据读取器 + if (topicInfo.dataReader == nullptr) { + return XNDDSErrorCode::DATAREADER_CREATE_FAILED; // 返回 + } + } else { + auto oldListener = topicInfo.dataReader->get_listener(); // 获取旧的监听器 + topicInfo.listener = + new XNDataReaderListenerImpl(fun); // 创建新的监听器 + topicInfo.dataReader->set_listener( + topicInfo.listener, + eprosima::fastdds::dds::StatusMask::all()); // 设置新的监听器 + delete oldListener; // 删除旧的监听器 + } + return XNDDSErrorCode::SUCCESS; + } + + /** + * @brief 注销订阅者, 带锁 + * @param topicName: 主题名称 + */ + void unregisterSubscriber(const std::string &topicName) + { + std::lock_guard locker(m_Mutex); + unregisterSubscriberWithoutLock(topicName); + } + + /** + * @brief 注销订阅者, 不带锁 + * @param topicName: 主题名称 + */ + void unregisterSubscriberWithoutLock(const std::string &topicName) + { + auto it = topics_.find(topicName); + if (it != topics_.end()) { + MonitorTopicInfo &topicInfo = it->second; // 获取主题信息 + if (topicInfo.dataReader != nullptr) { + topicInfo.subscriber->delete_datareader(topicInfo.dataReader); // 删除数据读取器 + topicInfo.dataReader = nullptr; // 设置数据读取器为空 + } + if (topicInfo.listener != nullptr) { + delete topicInfo.listener; // 删除监听器 + topicInfo.listener = nullptr; // 设置监听器为空 + } + if (topicInfo.subscriber != nullptr) { + m_Participant->delete_subscriber(topicInfo.subscriber); // 删除订阅者 + topicInfo.subscriber = nullptr; // 设置订阅者为空 + } + if (topicInfo.subscriber == nullptr && topicInfo.publisher == nullptr + && topicInfo.topic != nullptr) { + m_Participant->delete_topic(topicInfo.topic); // 删除主题 + topicInfo.topic = nullptr; // 设置主题为空 + topics_.erase(it); // 移除主题 + } + } + } + +private: + /** + * @brief 清除所有主题 + */ + void clearAllTopic() + { + std::lock_guard locker(m_Mutex); + if (m_Participant != nullptr) { + while (!topics_.empty()) { + unregisterPublisherWithoutLock(topics_.begin()->first); // 注销发布者 + unregisterSubscriberWithoutLock(topics_.begin()->first); // 注销订阅者 + } + } + } + +private: + /** + * @brief 单例指针 + */ + static TopicManager *instance; + + /** + * @brief 单例互斥锁 + */ + static std::mutex instanceMutex; + + /** + * @brief 参与者 + */ + XNParticipant *m_Participant = nullptr; + + /** + * @brief 主题映射 + */ + std::map topics_; + + /** + * @brief 主题访问互斥锁 + */ + std::mutex m_Mutex; +}; diff --git a/Release/include/XNMonitor/TypeDefine.h b/Release/include/XNMonitor/TypeDefine.h new file mode 100644 index 0000000..8cc00c0 --- /dev/null +++ b/Release/include/XNMonitor/TypeDefine.h @@ -0,0 +1,270 @@ +/** + * @file TypeDefine.h + * @brief 类型定义头文件 + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief 域参与者 + */ +using XNParticipant = eprosima::fastdds::dds::DomainParticipant; +/** + * @brief 域参与者Qos + */ +using XNParticipantQos = eprosima::fastdds::dds::DomainParticipantQos; +/** + * @brief 域参与者工厂 + */ +using XNParticipantFactory = eprosima::fastdds::dds::DomainParticipantFactory; +/** + * @brief 数据读取器监听器 + */ +using XNDataReaderListener = eprosima::fastdds::dds::DataReaderListener; +/** + * @brief 数据读取器 + */ +using XNDataReader = eprosima::fastdds::dds::DataReader; +/** + * @brief 数据读取器Qos + */ +using XNDataReaderQos = eprosima::fastdds::dds::DataReaderQos; +/** + * @brief 样本信息 + */ +using XNSampleInfo = eprosima::fastdds::dds::SampleInfo; +/** + * @brief 订阅者 + */ +using XNSubscriber = eprosima::fastdds::dds::Subscriber; +/** + * @brief 类型支持 + */ +using XNTypeSupport = eprosima::fastdds::dds::TypeSupport; +/** + * @brief 数据写入器 + */ +using XNDataWriter = eprosima::fastdds::dds::DataWriter; +/** + * @brief 数据写入器Qos + */ +using XNDataWriterQos = eprosima::fastdds::dds::DataWriterQos; +/** + * @brief 发布者 + */ +using XNPublisher = eprosima::fastdds::dds::Publisher; +/** + * @brief 发布者Qos + */ +using XNPublisherQos = eprosima::fastdds::dds::PublisherQos; +/** + * @brief 主题 + */ +using XNTopic = eprosima::fastdds::dds::Topic; +/** + * @brief 主题数据类型 + */ +using XNTopicDataType = eprosima::fastdds::dds::TopicDataType; + +using json = nlohmann::json; +/** + * @brief 主题信息 + */ +struct MonitorTopicInfo { + /** + * @brief 主题 + */ + XNTopic *topic; + /** + * @brief 发布者 + */ + XNPublisher *publisher; + /** + * @brief 数据写入器 + */ + XNDataWriter *dataWriter; + /** + * @brief 订阅者 + */ + XNSubscriber *subscriber; + /** + * @brief 数据读取器 + */ + XNDataReader *dataReader; + /** + * @brief 数据读取器监听器 + */ + XNDataReaderListener *listener; +}; + +// 错误码定义 +enum class XNDDSErrorCode { + SUCCESS = 0, + INIT_FAILED = -1, + TOPIC_CREATE_FAILED = -2, + PUBLISHER_CREATE_FAILED = -3, + SUBSCRIBER_CREATE_FAILED = -4, + DATAWRITER_CREATE_FAILED = -5, + DATAREADER_CREATE_FAILED = -6, + INVALID_PARAM = -7, + NOT_INITIALIZED = -8 +}; + +/** + * @brief 成员变量定义结构体 + * @note 成员变量包含数据类型、变量名、是否为数组、数组大小、描述 + */ +struct MemberVariable { + /** + * @brief 数据类型 + */ + std::string dataType; + /** + * @brief 变量名 + */ + std::string variableName; + /** + * @brief 是否为数组 + */ + bool isArray; + /** + * @brief 数组大小 + */ + std::vector arraySizes; + /** + * @brief 描述 + */ + std::string description; +}; + +/** + * @brief 接口结构体定义结构体 + * @note 接口结构体定义包含结构体名称、成员变量 + */ +struct StructDefinition { + /** + * @brief 结构体名称 + */ + std::string structName; + /** + * @brief 成员变量 + */ + std::vector> memberVariables; +}; + +/** + * @brief 命名空间定义结构体 + * @note 命名空间定义包含命名空间名称、接口结构体定义、子命名空间定义 + */ +struct NamespaceDefinition { + /** + * @brief 命名空间名称 + */ + std::string namespaceName; + /** + * @brief 结构体定义 + */ + std::vector> structDefinitions; + /** + * @brief 子命名空间 + */ + std::vector> childNamespaces; +}; + +/** + * @brief 模型接口定义 + * @note 模型接口定义包含模型名称和接口命名空间定义 + */ +struct ModelDefinition { + /** + * @brief 模型名称 + */ + std::string modelName; + /** + * @brief 命名空间定义 + */ + std::vector> namespaceDefinitions; +}; + +struct MonitorDataInfo { + /** + * @brief 结构体名称 + */ + std::string structName; + /** + * @brief 接口名称 + */ + std::vector interfaceNames; + + /** + * @brief 数组大小 + */ + std::vector> arraySizes; +}; + +struct CSVHeaderField { + /** + * @brief 字段名 + */ + std::string fieldName; + + /** + * @brief 结构体名称 + */ + std::string structName; + + /** + * @brief 数组维度 + */ + int arrayDim; + + /** + * @brief 数组索引1 + */ + int arrayIndex1; + + /** + * @brief 数组索引2 + */ + int arrayIndex2; + + /** + * @brief 列大小 + */ + int arraySize2; +}; \ No newline at end of file diff --git a/Release/include/XNMonitor/XNDataReaderListenerImpl.h b/Release/include/XNMonitor/XNDataReaderListenerImpl.h new file mode 100644 index 0000000..59aaa0d --- /dev/null +++ b/Release/include/XNMonitor/XNDataReaderListenerImpl.h @@ -0,0 +1,51 @@ +/** + * @file XNDataReaderListenerImpl.h + * @author jinchao + * @brief 数据读取器监听器模板类 + * @version 1.0 + * @date 2025-03-10 + * + * @copyright Copyright (c) 2025 COMAC + * + */ +#pragma once + +#include "TypeDefine.h" + +/** + * @brief 数据读取器监听器模板类 + * @tparam T 数据类型 + */ +template +class XNDataReaderListenerImpl : public XNDataReaderListener +{ +public: + /** + * @brief 构造函数 + * @param callback 回调函数 + */ + XNDataReaderListenerImpl(std::function callback) : callback_(callback) {} + + /** + * @brief 数据可用回调函数 + * @param reader 数据读取器 + */ + void on_data_available(XNDataReader *reader) override + { + XNSampleInfo info; + if (reader->take_next_sample(&data_, &info) == eprosima::fastdds::dds::RETCODE_OK + && info.valid_data) { + callback_(data_); + } + } + +private: + /** + * @brief 数据 + */ + T data_; + /** + * @brief 回调函数 + */ + std::function callback_; +}; \ No newline at end of file diff --git a/Release/include/XNMonitor/XNMonitorInterface.h b/Release/include/XNMonitor/XNMonitorInterface.h new file mode 100644 index 0000000..5be2d21 --- /dev/null +++ b/Release/include/XNMonitor/XNMonitorInterface.h @@ -0,0 +1,281 @@ +/** + * @file XNMonitorInterface.h + * @brief 监控服务器接口定义 + */ +#pragma once + +#include "TypeDefine.h" +#include "XNMonitorServer_global.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + /** + * @brief 初始化DDS监控服务器 + * @param domainId 域ID + * @param domainIdLen 域ID长度 + * @param confID 构型ID + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_Initialize(const char *domainId, int domainIdLen, int confID, + int forceGen, char *errorMsg, int errorMsgSize); + + /** + * @brief 清理DDS监控服务器 + */ + void XNMONITORSERVER_EXPORT XN_Cleanup(); + + //******************** 系统信息监控 ********************* + + /** + * @brief 启动监控系统信息 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StartMonitorSystemInfo(char *errorMsg, int errorMsgSize); + + /** + * @brief 获取系统信息 + * @param infoMsg 系统信息 + * @param infoMsgSize 系统信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_GetSystemInfo(char *infoMsg, int infoMsgSize); + + /** + * @brief 停止监控系统信息 + */ + void XNMONITORSERVER_EXPORT XN_StopMonitorSystemInfo(); + + //******************** 线程信息监控 ********************* + + /** + * @brief 获取所有线程信息 + * @param infoMsg 线程信息 + * @param infoMsgSize 线程信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_GetAllThreadInfo(char *infoMsg, int infoMsgSize); + + //******************** 模型信息监控 ********************* + + /** + * @brief 启动监控模型信息 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StartMonitorModelInfo(char *errorMsg, int errorMsgSize); + + /** + * @brief 获取模型信息 + * @param infoMsg 模型信息 + * @param infoMsgSize 模型信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_GetModelInfo(char *infoMsg, int infoMsgSize); + + /** + * @brief 停止监控模型信息 + */ + void XNMONITORSERVER_EXPORT XN_StopMonitorModelInfo(); + + //******************** 引擎控制 ********************* + + /** + * @brief 初始化引擎控制 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_InitializeEngineControl(char *errorMsg, int errorMsgSize); + + /** + * @brief 暂停引擎 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + */ + void XNMONITORSERVER_EXPORT XN_PauseEngine(char *errorMsg, int errorMsgSize); + + /** + * @brief 恢复引擎 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + void XNMONITORSERVER_EXPORT XN_ResumeEngine(char *errorMsg, int errorMsgSize); + + /** + * @brief 停止引擎 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + */ + void XNMONITORSERVER_EXPORT XN_StopEngine(char *errorMsg, int errorMsgSize); + + //******************** 数据监控 ********************* + + /** + * @brief 启动数据监控 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StartDataMonitor(const char *structName, const int structNameLen, + char *errorMsg, int errorMsgSize); + + /** + * @brief 停止数据监控 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + */ + void XNMONITORSERVER_EXPORT XN_StopDataMonitor(const char *structName, const int structNameLen, + char *errorMsg, int errorMsgSize); + + //******************** 数据注入 ********************* + + /** + * @brief 获取数据监控信息 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param interfaceName 接口名称JSON数组字符串 + * @param interfaceNameLen 接口名称JSON数组字符串长度 + * @param data 数据JSON字符串 + * @param dataLen 数据JSON字符串长度 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_GetDataMonitorInfo(const char *structName, + const int structNameLen, + const char *interfaceName, + const int interfaceNameLen, char *data, + int dataLen, char *infoMsg, int infoMsgSize); + + /** + * @brief 注入数据接口 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param interfaceNameAndData 接口名称和数据JSON字符串 + * @param interfaceNameAndDataLen 接口名称和数据JSON字符串长度 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_InjectDataInterface(const char *structName, + const int structNameLen, + const char *interfaceNameAndData, + const int interfaceNameAndDataLen, + char *infoMsg, int infoMsgSize); + + /** + * @brief 持续注入数据接口 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param interfaceNameAndData 接口名称和数据JSON字符串 + * @param interfaceNameAndDataLen 接口名称和数据JSON字符串长度 + * @param frequency 注入频率 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StartInjectContinuous( + const char *structName, const int structNameLen, const char *interfaceNameAndData, + const int interfaceNameAndDataLen, double frequency, char *infoMsg, int infoMsgSize); + + /** + * @brief 停止持续注入数据接口 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StopInjectContinuous(const char *structName, + const int structNameLen, char *infoMsg, + int infoMsgSize); + + //******************** csv数据注入 ********************* + + /** + * @brief 从csv文件中注入数据接口 + * @param structName 结构体名称 + * @param structNameLen 结构体名称长度 + * @param csvFilePath csv文件路径 + * @param csvFilePathLen csv文件路径长度 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *InjectDataInfo, + const int InjectDataInfoLen, + const char *csvFilePath, + const int csvFilePathLen, + char *infoMsg, int infoMsgSize); + + /** + * @brief 获取csv数据注入状态 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败, 1: 正在注入 + */ + int XNMONITORSERVER_EXPORT XN_GetCsvDataInjectStatus(char *infoMsg, int infoMsgSize); + + /** + * @brief 停止csv数据注入 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StopCsvDataInject(char *infoMsg, int infoMsgSize); + + //******************** csv数据采集 ********************* + + /** + * @brief 读取dcs采集脚本并将数据保存到csv文件接口 + * @param CollectDataInfo 采集数据信息JSON数组字符串 + * @param CollectDataInfoLen 采集数据信息JSON数组字符串长度 + * @param dcsFilePath dcs文件路径 + * @param dcsFilePathLen dcs文件路径长度 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StartCollectData(const char *CollectDataInfo, + const int CollectDataInfoLen, + const char *dcsFilePath, + const int dcsFilePathLen, char *infoMsg, + int infoMsgSize); + + /** + * @brief 获取csv数据采集状态 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败, 1: 正在采集 + */ + int XNMONITORSERVER_EXPORT XN_GetCollectDataStatus(char *infoMsg, int infoMsgSize); + + /** + * @brief 停止采集数据 + * @param infoMsg 错误信息 + * @param infoMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ + int XNMONITORSERVER_EXPORT XN_StopCollectData(char *infoMsg, int infoMsgSize); + + /** + * @brief 清理所有资源 + */ + void XNMONITORSERVER_EXPORT XN_Cleanup(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/Release/include/XNMonitor/XNMonitorServer_global.h b/Release/include/XNMonitor/XNMonitorServer_global.h new file mode 100644 index 0000000..b8cd139 --- /dev/null +++ b/Release/include/XNMonitor/XNMonitorServer_global.h @@ -0,0 +1,7 @@ +#pragma once + +#ifdef XNMonitorServer_EXPORTS +# define XNMONITORSERVER_EXPORT __attribute__((visibility("default"))) +#else +# define XNMONITORSERVER_EXPORT __attribute__((visibility("default"))) +#endif diff --git a/XNModelGenServer/XNModelGen.cpp b/XNModelGenServer/XNModelGen.cpp index 6e83f00..14d7171 100644 --- a/XNModelGenServer/XNModelGen.cpp +++ b/XNModelGenServer/XNModelGen.cpp @@ -439,10 +439,11 @@ bool XNModelGen::GenerateSourceFile() sourceFile << "void " << m_className << "::ReleaseData() {" << std::endl; sourceFile << " T_D();" << std::endl; if (!m_inputStructName.structName.empty()) { - sourceFile << " // TODO: 在这里释放输入数据" << std::endl; - sourceFile << std::endl; + if (m_inputStructName.isPointer) { sourceFile << " if (d->_data." << m_inputStructName.structName << ") {" << std::endl; + sourceFile << " // TODO: 在这里释放输入数据" << std::endl; + sourceFile << std::endl; sourceFile << " delete d->_data." << m_inputStructName.structName << ";" << std::endl; sourceFile << " d->_data." << m_inputStructName.structName << " = nullptr;" @@ -451,11 +452,11 @@ bool XNModelGen::GenerateSourceFile() } } if (!m_outputStructName.structName.empty()) { - sourceFile << " // TODO: 在这里释放输出数据" << std::endl; - sourceFile << std::endl; if (m_outputStructName.isPointer) { sourceFile << " if (d->_data." << m_outputStructName.structName << ") {" << std::endl; + sourceFile << " // TODO: 在这里释放输出数据" << std::endl; + sourceFile << std::endl; sourceFile << " delete d->_data." << m_outputStructName.structName << ";" << std::endl; sourceFile << " d->_data." << m_outputStructName.structName << " = nullptr;" diff --git a/XNMonitorServer/.vscode/settings.json b/XNMonitorServer/.vscode/settings.json index fc63933..d7747f7 100644 --- a/XNMonitorServer/.vscode/settings.json +++ b/XNMonitorServer/.vscode/settings.json @@ -73,6 +73,7 @@ "any": "cpp", "forward_list": "cpp", "fstream": "cpp", - "valarray": "cpp" + "valarray": "cpp", + "*.ipp": "cpp" } } diff --git a/XNMonitorServer/CMakeLists.txt b/XNMonitorServer/CMakeLists.txt index 00194e4..a57eae7 100644 --- a/XNMonitorServer/CMakeLists.txt +++ b/XNMonitorServer/CMakeLists.txt @@ -20,12 +20,11 @@ else() message(FATAL_ERROR "Environment variable XNCore is not set.") endif() -# file(GLOB DDS_XNIDL_SOURCES_CXX "../XNCore/XNIDL/*.cxx") include_directories(${XNCore_PATH}/include) -include_directories(${XNCore_PATH}/Configuration/C909_V1) find_package(OpenSSL REQUIRED) find_package(nlohmann_json 3.9.1 REQUIRED) +find_package(SQLite3 REQUIRED) add_library(XNMonitorServer SHARED XNMonitorServer_global.h @@ -50,6 +49,11 @@ add_library(XNMonitorServer SHARED CSVDataInjectThread.cpp DataCollect.h DataCollect.cpp + PluginManager.h + PluginManager.cpp + PluginInterface.h + PluginGenerator.h + PluginGenerator.cpp ) # 添加头文件搜索路径 @@ -61,8 +65,9 @@ target_link_libraries(XNMonitorServer PRIVATE fastdds OpenSSL::SSL OpenSSL::Crypto + SQLite::SQLite3 ${XNCore_PATH}/lib/libXNCore.so - ${XNCore_PATH}/lib/libC909_V1_Interface.so + dl ) target_compile_definitions(XNMonitorServer PRIVATE XNMONITOR_SERVER_LIBRARY) @@ -77,3 +82,9 @@ install(TARGETS XNMonitorServer LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION . ) + +#添加自定义命令和目标以拷贝所有头文件 +file(GLOB HEADER_FILES "*.h") + +# 使用 install 命令在安装时拷贝头文件 +install(FILES ${HEADER_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/XNMonitor) diff --git a/XNMonitorServer/DataMonitorFactory.cpp b/XNMonitorServer/DataMonitorFactory.cpp index d142fe0..6dee257 100644 --- a/XNMonitorServer/DataMonitorFactory.cpp +++ b/XNMonitorServer/DataMonitorFactory.cpp @@ -1,6 +1,24 @@ #include "DataMonitorFactory.h" +#include "PluginManager.h" -// 静态成员初始化 -std::mutex DataMonitorFactory::mutex_; +DataMonitorBasePtr DataMonitorFactory::GetInstance(const std::string &interfaceName) +{ + return PluginManager::Instance().GetMonitor(interfaceName); +} -std::unordered_map DataMonitorFactory::instances_; \ No newline at end of file +void DataMonitorFactory::ReleaseInstance(const std::string &interfaceName) +{ + // 插件管理器会自动管理实例生命周期 + // 这里可以添加额外的清理逻辑 +} + +bool DataMonitorFactory::HasInterface(const std::string &interfaceName) +{ + auto interfaces = PluginManager::Instance().GetSupportedInterfaces(); + return std::find(interfaces.begin(), interfaces.end(), interfaceName) != interfaces.end(); +} + +std::vector DataMonitorFactory::GetRegisteredInterfaces() +{ + return PluginManager::Instance().GetSupportedInterfaces(); +} \ No newline at end of file diff --git a/XNMonitorServer/DataMonitorFactory.h b/XNMonitorServer/DataMonitorFactory.h index b412961..a981523 100644 --- a/XNMonitorServer/DataMonitorFactory.h +++ b/XNMonitorServer/DataMonitorFactory.h @@ -3,108 +3,23 @@ #include "XNMonitorServer_global.h" #include "DataMonitor.h" -//接口头文件 -#include - /** * @brief DataMonitor工厂类,用于创建不同类型的DataMonitor实例 */ class XNMONITORSERVER_EXPORT DataMonitorFactory { public: - static DataMonitorBasePtr GetInstance(const std::string &interfaceName) - { - if (interfaceName == "Aerodynamics_heartbeat") { - return GetInstance(); - } else if (interfaceName == "Aerodynamics_input") { - return GetInstance(); - } else if (interfaceName == "Aerodynamics_output") { - return GetInstance(); - } else if (interfaceName == "GroundHandling_heartbeat") { - return GetInstance(); - } else if (interfaceName == "GroundHandling_input") { - return GetInstance(); - } else if (interfaceName == "GroundHandling_output") { - return GetInstance(); - } else if (interfaceName == "WeightBalance_heartbeat") { - return GetInstance(); - } else if (interfaceName == "WeightBalance_input") { - return GetInstance(); - } else if (interfaceName == "WeightBalance_output") { - return GetInstance(); - } - return nullptr; - } + static DataMonitorBasePtr GetInstance(const std::string &interfaceName); - static void ReleaseInstance(const std::string &interfaceName) - { - if (interfaceName == "Aerodynamics_heartbeat") { - ReleaseInstance(); - } else if (interfaceName == "Aerodynamics_input") { - ReleaseInstance(); - } else if (interfaceName == "Aerodynamics_output") { - ReleaseInstance(); - } else if (interfaceName == "GroundHandling_heartbeat") { - ReleaseInstance(); - } else if (interfaceName == "GroundHandling_input") { - ReleaseInstance(); - } else if (interfaceName == "GroundHandling_output") { - ReleaseInstance(); - } else if (interfaceName == "WeightBalance_heartbeat") { - ReleaseInstance(); - } else if (interfaceName == "WeightBalance_input") { - ReleaseInstance(); - } else if (interfaceName == "WeightBalance_output") { - ReleaseInstance(); - } - } + static void ReleaseInstance(const std::string &interfaceName); -private: - /** - * @brief 创建DataMonitor实例 - * @param framework 框架指针 - * @param modelId 模型ID - * @param DDS_type DDS类型 - * @return 返回创建的DataMonitor实例的智能指针 - */ - template - static DataMonitorBasePtr GetInstance() - { - std::lock_guard lock(mutex_); + // 检查接口是否存在 + static bool HasInterface(const std::string &interfaceName); - // 使用type_index作为键,更可靠的类型标识 - std::type_index typeIndex(typeid(T)); - - // 检查是否已存在实例 - auto it = instances_.find(typeIndex); - if (it != instances_.end()) { - return it->second; - } - - // 创建新实例 - auto monitor = std::make_shared>(); - instances_[typeIndex] = monitor; - return monitor; - } - - /** - * @brief 释放指定类型的实例 - */ - template - static void ReleaseInstance() - { - std::lock_guard lock(mutex_); - std::type_index typeIndex(typeid(T)); - if (instances_.find(typeIndex) == instances_.end()) { - return; - } - instances_.erase(typeIndex); - } + // 获取所有已注册的接口名称 + static std::vector GetRegisteredInterfaces(); private: DataMonitorFactory() = delete; ~DataMonitorFactory() = delete; - - static std::mutex mutex_; - static std::unordered_map instances_; }; diff --git a/XNMonitorServer/PluginGenerator.cpp b/XNMonitorServer/PluginGenerator.cpp new file mode 100644 index 0000000..5509e35 --- /dev/null +++ b/XNMonitorServer/PluginGenerator.cpp @@ -0,0 +1,379 @@ +/** + * @file PluginGenerator.cpp + * @brief 简化的插件生成器实现 + */ +#include "PluginGenerator.h" + +std::string GetXNCorePath() +{ + const char *xnCorePath = std::getenv("XNCore"); + if (xnCorePath != nullptr) { + return std::string(xnCorePath); + } + return ""; +} + +PluginGenerator::PluginGenerator() +{ +} + +PluginGenerator::~PluginGenerator() +{ +} + +bool PluginGenerator::loadPluginFromDatabase(const int confID) +{ + std::string xncorePath = GetXNCorePath(); + if (xncorePath.empty()) { + m_lastError = "无法获取XNCore环境变量的值!"; + return false; + } + + std::string dbPath = xncorePath + "/database/XNSim.db"; + if (!std::filesystem::exists(dbPath)) { + m_lastError = "数据库文件不存在!"; + return false; + } + + sqlite3 *db = nullptr; + int rc = sqlite3_open(dbPath.c_str(), &db); + if (rc != SQLITE_OK) { + m_lastError = "无法打开数据库: " + std::string(sqlite3_errmsg(db)); + sqlite3_close(db); + return false; + } + + // 准备SQL语句查询Configuration表 + const char *sql = "SELECT ConfName FROM Configuration WHERE ConfID = ?"; + sqlite3_stmt *stmt = nullptr; + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); + if (rc != SQLITE_OK) { + m_lastError = "SQL准备失败: " + std::string(sqlite3_errmsg(db)); + sqlite3_close(db); + return false; + } + + // 绑定参数 + sqlite3_bind_int(stmt, 1, confID); + + // 执行查询 + if (sqlite3_step(stmt) == SQLITE_ROW) { + const char *text = reinterpret_cast(sqlite3_column_text(stmt, 0)); + m_pluginInfo.pluginName = text ? text : ""; + m_pluginInfo.interfaceHeaderPath = "../IDL/" + m_pluginInfo.pluginName + "_Interface.h"; + m_pluginInfo.outputDirectory = + xncorePath + "/Configuration/" + m_pluginInfo.pluginName + "/PluginCode"; + } else { + m_lastError = "未找到ConfID为 " + std::to_string(confID) + " 的配置"; + sqlite3_finalize(stmt); + sqlite3_close(db); + return false; + } + + // 清理资源 + sqlite3_finalize(stmt); + + // 查询DataInterface_{ConfID}表获取接口信息 + std::string dataInterfaceTableName = "DataInterface_" + std::to_string(confID); + std::string dataInterfaceSql = + "SELECT DISTINCT ModelStructName, SystemName, PlaneName, ATAName FROM " + + dataInterfaceTableName; + + sqlite3_stmt *dataInterfaceStmt = nullptr; + rc = sqlite3_prepare_v2(db, dataInterfaceSql.c_str(), -1, &dataInterfaceStmt, nullptr); + if (rc != SQLITE_OK) { + m_lastError = "DataInterface表SQL准备失败: " + std::string(sqlite3_errmsg(db)); + sqlite3_close(db); + return false; + } + + // 执行查询并收集接口信息 + while (sqlite3_step(dataInterfaceStmt) == SQLITE_ROW) { + InterfaceInfo interface; + interface.interfaceName = + reinterpret_cast(sqlite3_column_text(dataInterfaceStmt, 0)); + std::string systemName = + reinterpret_cast(sqlite3_column_text(dataInterfaceStmt, 1)); + std::string planeName = + reinterpret_cast(sqlite3_column_text(dataInterfaceStmt, 2)); + std::string ataName = + reinterpret_cast(sqlite3_column_text(dataInterfaceStmt, 3)); + interface.templateType = systemName + "::" + planeName + "::" + ataName + + "::" + interface.interfaceName + "_Interface"; + + // 使用ModelStructName去重 + bool isDuplicate = false; + for (const auto &existingInterface : m_pluginInfo.interfaces) { + if (existingInterface.interfaceName == interface.interfaceName) { + isDuplicate = true; + break; + } + } + + if (!isDuplicate) { + m_pluginInfo.interfaces.push_back(interface); + } + } + + // 清理DataInterface查询资源 + sqlite3_finalize(dataInterfaceStmt); + sqlite3_close(db); + return true; +} + +bool PluginGenerator::generatePluginCpp() +{ + std::string content = generatePluginCppContent(); + std::string filePath = + m_pluginInfo.outputDirectory + "/" + m_pluginInfo.pluginName + "_plugin.cpp"; + return writeFile(filePath, content); +} + +bool PluginGenerator::generateCMakeLists() +{ + std::string content = generateCMakeListsContent(); + std::string filePath = m_pluginInfo.outputDirectory + "/CMakeLists.txt"; + return writeFile(filePath, content); +} + +bool PluginGenerator::compilePlugin() +{ + std::string buildDir = m_pluginInfo.outputDirectory + "/build"; + // 如果build目录已存在则删除 + if (std::filesystem::exists(buildDir)) { + try { + std::filesystem::remove_all(buildDir); + } catch (const std::exception &e) { + m_lastError = "Failed to remove existing build directory: " + std::string(e.what()); + return false; + } + } + // 创建build目录 + if (!createDirectory(buildDir)) { + m_lastError = "Failed to create build directory: " + buildDir; + return false; + } + + // 构建命令 + std::string cmakeCmd = "cd " + buildDir + " && cmake .."; + std::string makeCmd = "cd " + buildDir + " && make"; + std::string installCmd = "cd " + buildDir + " && make install"; + + // 执行cmake + int cmakeResult = system(cmakeCmd.c_str()); + if (cmakeResult != 0) { + m_lastError = "CMake failed with exit code: " + std::to_string(cmakeResult); + return false; + } + + // 执行make + int makeResult = system(makeCmd.c_str()); + if (makeResult != 0) { + m_lastError = "Make failed with exit code: " + std::to_string(makeResult); + return false; + } + + // 执行make install + int installResult = system(installCmd.c_str()); + if (installResult != 0) { + m_lastError = "Make install failed with exit code: " + std::to_string(installResult); + return false; + } + + return true; +} + +std::string PluginGenerator::getLastError() const +{ + return m_lastError; +} + +std::string PluginGenerator::generatePluginCppContent() +{ + std::stringstream ss; + + // 生成头文件包含 + ss << "#include \n"; + ss << "#include \n"; + ss << "// " << m_pluginInfo.pluginName << "接口头文件 - 只在插件中包含\n"; + ss << "#include \"" << m_pluginInfo.interfaceHeaderPath << "\"\n\n"; + + // 生成插件信息 + ss << "// 插件信息\n"; + ss << "static PluginInfo plugin_info = {\"" << m_pluginInfo.pluginName << "\", \"" + << "" << "\", DATAMONITOR_PLUGIN_INTERFACE_VERSION};\n\n"; + + // 生成支持的接口列表 + ss << "// 支持的接口列表\n"; + ss << "static const char *supported_interfaces[] = {\n"; + for (size_t i = 0; i < m_pluginInfo.interfaces.size(); ++i) { + ss << " \"" << m_pluginInfo.interfaces[i].interfaceName << "\""; + if (i < m_pluginInfo.interfaces.size() - 1) { + ss << ","; + } + ss << "\n"; + } + ss << "};\n\n"; + + ss << "static const int interface_count = sizeof(supported_interfaces) / " + "sizeof(supported_interfaces[0]);\n\n"; + + // 生成导出的插件函数 + ss << "// 导出的插件函数\n"; + ss << "extern \"C\"\n"; + ss << "{\n\n"; + + // get_plugin_info函数 + ss << " PluginInfo *get_plugin_info()\n"; + ss << " {\n"; + ss << " return &plugin_info;\n"; + ss << " }\n\n"; + + // create_monitor函数 + ss << " DataMonitorBasePtr create_monitor(const char *interfaceName)\n"; + ss << " {\n"; + ss << " std::string name(interfaceName);\n\n"; + + for (size_t i = 0; i < m_pluginInfo.interfaces.size(); ++i) { + const auto &interface = m_pluginInfo.interfaces[i]; + ss << " if (name == \"" << interface.interfaceName << "\") {\n"; + ss << " return std::make_shared>();\n"; + ss << " }"; + if (i < m_pluginInfo.interfaces.size() - 1) { + ss << " else"; + } + ss << "\n"; + } + + ss << " return nullptr;\n"; + ss << " }\n\n"; + + // destroy_monitor函数 + ss << " void destroy_monitor(const char *interfaceName)\n"; + ss << " {\n"; + ss << " // 智能指针会自动管理内存,这里可以添加额外的清理逻辑\n"; + ss << " }\n\n"; + + // get_supported_interfaces函数 + ss << " const char **get_supported_interfaces(int *count)\n"; + ss << " {\n"; + ss << " if (count) {\n"; + ss << " *count = interface_count;\n"; + ss << " }\n"; + ss << " return const_cast(supported_interfaces);\n"; + ss << " }\n\n"; + + // free_string_array函数 + ss << " void free_string_array(const char **array)\n"; + ss << " {\n"; + ss << " // 这里不需要释放,因为使用的是静态数组\n"; + ss << " }\n"; + ss << "}\n"; + + return ss.str(); +} + +std::string PluginGenerator::generateCMakeListsContent() +{ + std::stringstream ss; + std::string projectName = m_pluginInfo.pluginName + "_Monitor"; + + ss << "# CMakeLists.txt for " << projectName << " plugin\n"; + ss << "cmake_minimum_required(VERSION 3.10)\n\n"; + + ss << "# 设置项目名称\n"; + ss << "project(" << projectName << "_plugin)\n\n"; + + ss << "# 设置C++标准\n"; + ss << "set(CMAKE_CXX_STANDARD 17)\n"; + ss << "set(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n"; + + ss << "# 查找必要的包\n"; + ss << "find_package(PkgConfig REQUIRED)\n"; + ss << "find_package(FastDDS REQUIRED)\n"; + + ss << "if(DEFINED ENV{XNCore})\n"; + ss << " set(XNCore_PATH $ENV{XNCore})\n"; + ss << "else()\n"; + ss << " message(FATAL_ERROR \"Environment variable XNCore is not set.\")\n"; + ss << "endif()\n"; + + ss << "include_directories(${XNCore_PATH}/include)\n"; + + ss << "# 创建插件库\n"; + ss << "add_library(" << projectName << " SHARED\n"; + ss << " " << m_pluginInfo.pluginName << "_plugin.cpp\n"; + ss << ")\n\n"; + + ss << "# 链接库\n"; + ss << "target_link_libraries(" << projectName << "\n"; + ss << " fastcdr\n"; + ss << " fastdds\n"; + ss << " OpenSSL::SSL\n"; + ss << " OpenSSL::Crypto\n"; + ss << " ${XNCore_PATH}/lib/lib" << m_pluginInfo.pluginName << "_Interface.so\n"; + ss << " ${XNCore_PATH}/lib/libXNMonitorServer.so\n"; + ss << ")\n\n"; + + ss << "target_compile_definitions(" << projectName << " PRIVATE " << projectName + << "_LIBRARY)\n"; + + ss << "if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n"; + ss << " set(CMAKE_INSTALL_PREFIX \"${XNCore_PATH}/Configuration/" << m_pluginInfo.pluginName + << "/Plugins\" CACHE PATH \"Install path prefix\" " + "FORCE)\n"; + ss << "endif()\n"; + + ss << "include(GNUInstallDirs)\n"; + ss << "install(TARGETS " << projectName << "\n"; + ss << " BUNDLE DESTINATION .\n"; + ss << " LIBRARY DESTINATION .\n"; + ss << " RUNTIME DESTINATION .\n"; + ss << ")\n"; + + return ss.str(); +} + +bool PluginGenerator::writeFile(const std::string &filePath, const std::string &content) +{ + try { + // 确保目录存在 + std::filesystem::path path(filePath); + if (path.has_parent_path()) { + createDirectory(path.parent_path().string()); + } + + std::ofstream file(filePath); + if (!file.is_open()) { + m_lastError = "无法创建文件: " + filePath; + return false; + } + + file << content; + file.close(); + + return true; + } catch (const std::exception &e) { + m_lastError = "写入文件错误: " + std::string(e.what()); + return false; + } +} + +bool PluginGenerator::createDirectory(const std::string &dirPath) +{ + try { + if (!std::filesystem::exists(dirPath)) { + return std::filesystem::create_directories(dirPath); + } + return true; + } catch (const std::exception &e) { + m_lastError = "创建目录错误: " + std::string(e.what()); + return false; + } +} + +const GenPluginInfo &PluginGenerator::getPluginInfo() const +{ + return m_pluginInfo; +} \ No newline at end of file diff --git a/XNMonitorServer/PluginGenerator.h b/XNMonitorServer/PluginGenerator.h new file mode 100644 index 0000000..e2ed0ce --- /dev/null +++ b/XNMonitorServer/PluginGenerator.h @@ -0,0 +1,66 @@ +/** + * @file PluginGenerator.h + * @brief 简化的插件生成器 - 从数据库生成插件cpp文件和CMakeLists + */ + +#pragma once +#include "TypeDefine.h" + +// 接口信息结构 +struct InterfaceInfo { + std::string interfaceName; // 接口名称(如:Aerodynamics_heartbeat) + std::string + templateType; // 模板类型(如:XNSim::C909::ATA04::Aerodynamics_heartbeat_Interface) +}; + +// 插件信息 +struct GenPluginInfo { + std::string pluginName; // 插件名称(如:C909_V1) + std::string pluginDescription; // 插件描述 + std::string interfaceHeaderPath; // 接口头文件路径(如:IDL/C909_V1_Interface.h) + std::vector interfaces; // 接口列表 + std::string outputDirectory; // 输出目录 +}; + +class PluginGenerator +{ +public: + PluginGenerator(); + ~PluginGenerator(); + + // 从数据库加载插件信息 + bool loadPluginFromDatabase(const int confID); + + // 生成插件cpp文件 + bool generatePluginCpp(); + + // 生成CMakeLists.txt + bool generateCMakeLists(); + + // 编译插件 + bool compilePlugin(); + + // 获取错误信息 + std::string getLastError() const; + + // 获取插件信息 + const GenPluginInfo &getPluginInfo() const; + +private: + // 生成插件cpp文件内容 + std::string generatePluginCppContent(); + + // 生成CMakeLists.txt内容 + std::string generateCMakeListsContent(); + + // 写入文件 + bool writeFile(const std::string &filePath, const std::string &content); + + // 创建目录 + bool createDirectory(const std::string &dirPath); + +private: + std::string m_lastError; + + GenPluginInfo m_pluginInfo; +}; diff --git a/XNMonitorServer/PluginInterface.h b/XNMonitorServer/PluginInterface.h new file mode 100644 index 0000000..c5c10ed --- /dev/null +++ b/XNMonitorServer/PluginInterface.h @@ -0,0 +1,34 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "DataMonitor.h" +#include "TypeDefine.h" + +// 插件信息结构 +struct PluginInfo { + const char *name; // 插件名称,如 "C909_V1" + const char *description; // 描述信息 + const char *interface_version; // 接口版本,必须与主项目兼容 +}; + +// C风格插件接口 - 确保ABI兼容性 +extern "C" +{ + // 获取插件信息 + typedef PluginInfo *(*GetPluginInfoFunc)(); + + // 创建监控器实例 + typedef DataMonitorBasePtr (*CreateMonitorFunc)(const char *interfaceName); + + // 销毁监控器实例 + typedef void (*DestroyMonitorFunc)(const char *interfaceName); + + // 获取支持的接口列表 + typedef const char **(*GetSupportedInterfacesFunc)(int *count); + + // 释放字符串数组 + typedef void (*FreeStringArrayFunc)(const char **array); +} + +// 插件接口版本 - 主项目一旦发布就不再修改 +#define DATAMONITOR_PLUGIN_INTERFACE_VERSION "1.0.0" \ No newline at end of file diff --git a/XNMonitorServer/PluginManager.cpp b/XNMonitorServer/PluginManager.cpp new file mode 100644 index 0000000..e3283e5 --- /dev/null +++ b/XNMonitorServer/PluginManager.cpp @@ -0,0 +1,126 @@ +#include "PluginManager.h" + +PluginManager &PluginManager::Instance() +{ + static PluginManager instance; + return instance; +} + +PluginManager::~PluginManager() +{ + UnloadCurrentPlugin(); +} + +void PluginManager::SetGeneratedPluginInfo(const GenPluginInfo &pluginInfo) +{ + m_generatedPluginInfo = pluginInfo; +} + +bool PluginManager::LoadPluginFromGenerator() +{ + if (m_generatedPluginInfo.pluginName.empty()) { + return false; + } + + // 构建插件路径 - 安装到outputDirectory上级目录的Plugins下 + std::filesystem::path outputPath(m_generatedPluginInfo.outputDirectory); + std::string pluginPath = outputPath.parent_path().string() + "/Plugins/lib" + + m_generatedPluginInfo.pluginName + "_Monitor.so"; + + // 卸载当前插件 + UnloadCurrentPlugin(); + + // 加载插件库 + m_pluginHandle = dlopen(pluginPath.c_str(), RTLD_LAZY); + if (!m_pluginHandle) { + std::cerr << "Failed to load plugin: " << dlerror() << std::endl; + return false; + } + + // 获取插件函数 + m_getPluginInfoFunc = + reinterpret_cast(dlsym(m_pluginHandle, "get_plugin_info")); + m_createMonitorFunc = + reinterpret_cast(dlsym(m_pluginHandle, "create_monitor")); + m_destroyMonitorFunc = + reinterpret_cast(dlsym(m_pluginHandle, "destroy_monitor")); + m_getSupportedInterfacesFunc = reinterpret_cast( + dlsym(m_pluginHandle, "get_supported_interfaces")); + m_freeStringArrayFunc = + reinterpret_cast(dlsym(m_pluginHandle, "free_string_array")); + + // 检查函数是否都加载成功 + if (!m_getPluginInfoFunc || !m_createMonitorFunc || !m_getSupportedInterfacesFunc) { + std::cerr << "Failed to load plugin functions" << std::endl; + UnloadCurrentPlugin(); + return false; + } + + // 获取插件信息 + m_pluginInfo = m_getPluginInfoFunc(); + + return true; +} + +void PluginManager::UnloadCurrentPlugin() +{ + // 先清理监控器缓存(这会触发DataMonitorProduct的析构函数) + m_monitorCache.clear(); + + if (m_pluginHandle) { + dlclose(m_pluginHandle); + m_pluginHandle = nullptr; + } + m_pluginInfo = nullptr; + m_getPluginInfoFunc = nullptr; + m_createMonitorFunc = nullptr; + m_destroyMonitorFunc = nullptr; + m_getSupportedInterfacesFunc = nullptr; + m_freeStringArrayFunc = nullptr; +} + +DataMonitorBasePtr PluginManager::GetMonitor(const std::string &interfaceName) +{ + if (!m_createMonitorFunc) { + return nullptr; + } + + // 检查缓存中是否已有实例 + auto it = m_monitorCache.find(interfaceName); + if (it != m_monitorCache.end()) { + return it->second; + } + + // 创建新实例(不自动初始化) + auto monitor = m_createMonitorFunc(interfaceName.c_str()); + + // 缓存实例 + if (monitor) { + m_monitorCache[interfaceName] = monitor; + } + + return monitor; +} + +std::vector PluginManager::GetSupportedInterfaces() +{ + std::vector interfaces; + + if (!m_getSupportedInterfacesFunc) { + return interfaces; + } + + int count = 0; + const char **interfaceNames = m_getSupportedInterfacesFunc(&count); + + for (int i = 0; i < count; ++i) { + interfaces.push_back(interfaceNames[i]); + } + + return interfaces; +} + +bool PluginManager::IsPluginLoaded() const +{ + return m_pluginHandle != nullptr && m_createMonitorFunc != nullptr; +} \ No newline at end of file diff --git a/XNMonitorServer/PluginManager.h b/XNMonitorServer/PluginManager.h new file mode 100644 index 0000000..7f8bbf3 --- /dev/null +++ b/XNMonitorServer/PluginManager.h @@ -0,0 +1,51 @@ +#pragma once + +#include "XNMonitorServer_global.h" +#include "PluginInterface.h" +#include "PluginGenerator.h" +#include "TypeDefine.h" + +class XNMONITORSERVER_EXPORT PluginManager +{ +public: + static PluginManager &Instance(); + + // 设置生成的插件信息 + void SetGeneratedPluginInfo(const GenPluginInfo &pluginInfo); + + // 从生成器加载插件 + bool LoadPluginFromGenerator(); + + // 卸载当前插件 + void UnloadCurrentPlugin(); + + // 获取监控器实例 + DataMonitorBasePtr GetMonitor(const std::string &interfaceName); + + // 获取所有支持的接口 + std::vector GetSupportedInterfaces(); + + // 检查插件是否已加载 + bool IsPluginLoaded() const; + +private: + PluginManager() = default; + ~PluginManager(); + PluginManager(const PluginManager &) = delete; + PluginManager &operator=(const PluginManager &) = delete; + + // 当前加载的插件信息 + void *m_pluginHandle = nullptr; + PluginInfo *m_pluginInfo = nullptr; + GetPluginInfoFunc m_getPluginInfoFunc = nullptr; + CreateMonitorFunc m_createMonitorFunc = nullptr; + DestroyMonitorFunc m_destroyMonitorFunc = nullptr; + GetSupportedInterfacesFunc m_getSupportedInterfacesFunc = nullptr; + FreeStringArrayFunc m_freeStringArrayFunc = nullptr; + + // 生成的插件信息 + GenPluginInfo m_generatedPluginInfo; + + // 监控器实例缓存 + std::unordered_map m_monitorCache; +}; \ No newline at end of file diff --git a/XNMonitorServer/SystemControl.cpp b/XNMonitorServer/SystemControl.cpp index 3f354ea..3d10b8a 100644 --- a/XNMonitorServer/SystemControl.cpp +++ b/XNMonitorServer/SystemControl.cpp @@ -1,5 +1,5 @@ #include "SystemControl.h" -#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp" +#include "XNIDL/XNSimStatusPubSubTypes.hpp" SystemControl::~SystemControl() { diff --git a/XNMonitorServer/TypeDefine.h b/XNMonitorServer/TypeDefine.h index b7f51e7..8cc00c0 100755 --- a/XNMonitorServer/TypeDefine.h +++ b/XNMonitorServer/TypeDefine.h @@ -16,6 +16,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/XNMonitorServer/XNMonitorInterface.cpp b/XNMonitorServer/XNMonitorInterface.cpp index cdc8c13..db137ee 100644 --- a/XNMonitorServer/XNMonitorInterface.cpp +++ b/XNMonitorServer/XNMonitorInterface.cpp @@ -10,6 +10,8 @@ #include "DataInjectThread.h" #include "CSVDataInjectThread.h" #include "DataCollect.h" +#include "PluginManager.h" +#include "PluginGenerator.h" // 全局变量 static bool g_initialized = false; @@ -25,10 +27,19 @@ std::unordered_map g_dataInjectThreads; CSVDataInjectThread *g_csvDataInjectThread = nullptr; DataCollect *g_dataCollect = nullptr; -// 初始化函数实现 -int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int errorMsgSize) -{ +/** + * @brief 生成插件 + * @param confID 构型ID + * @param errorMsg 错误信息 + * @param errorMsgSize 错误信息大小 + * @return 0: 成功, -1: 失败 + */ +int XN_GenPlugin(int confID, int forceGen, char *errorMsg, int errorMsgSize); +// 初始化函数实现 +int XN_Initialize(const char *domainId, int domainIdLen, int confID, int forceGen, char *errorMsg, + int errorMsgSize) +{ if (g_initialized) { if (errorMsg && errorMsgSize > 0) { strncpy(errorMsg, "DDSMonitor Initialized Successfully", errorMsgSize - 1); @@ -56,6 +67,12 @@ int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int err return -1; } + // 生成插件 + if (XN_GenPlugin(confID, forceGen, errorMsg, errorMsgSize) != 0) { + return -1; + } + + // 先初始化DDS参与者 XNDDSErrorCode ret = TopicManager::Instance()->initializeParticipant(domainIdInt); if (ret != XNDDSErrorCode::SUCCESS) { if (errorMsg && errorMsgSize > 0) { @@ -67,6 +84,19 @@ int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int err return -1; } + // 初始化插件管理器 + auto &pluginManager = PluginManager::Instance(); + + // 加载生成的插件 + if (!pluginManager.LoadPluginFromGenerator()) { + if (errorMsg && errorMsgSize > 0) { + std::string error = "Failed to load generated plugin"; + strncpy(errorMsg, error.c_str(), errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return -1; + } + g_initialized = true; if (errorMsg && errorMsgSize > 0) { strncpy(errorMsg, "DDSMonitor Initialized Successfully", errorMsgSize - 1); @@ -855,8 +885,6 @@ int XN_StopCollectData(char *infoMsg, int infoMsgSize) try { g_dataCollect->stop(); - delete g_dataCollect; - g_dataCollect = nullptr; } catch (const std::exception &e) { if (infoMsg && infoMsgSize > 0) { strncpy(infoMsg, e.what(), infoMsgSize - 1); @@ -876,6 +904,75 @@ void XN_CleanupDataCollect() g_dataCollect = nullptr; } } + +// 生成插件函数实现 +int XN_GenPlugin(int confID, int forceGen, char *errorMsg, int errorMsgSize) +{ + try { + // 创建插件生成器 + PluginGenerator generator; + + // 从数据库加载插件信息 + if (!generator.loadPluginFromDatabase(confID)) { + if (errorMsg && errorMsgSize > 0) { + std::string error = + "Failed to load plugin info from database: " + generator.getLastError(); + strncpy(errorMsg, error.c_str(), errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return -1; + } + if (forceGen == 1) { + // 生成插件cpp文件 + if (!generator.generatePluginCpp()) { + if (errorMsg && errorMsgSize > 0) { + std::string error = + "Failed to generate plugin cpp: " + generator.getLastError(); + strncpy(errorMsg, error.c_str(), errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return -1; + } + + // 生成CMakeLists.txt + if (!generator.generateCMakeLists()) { + if (errorMsg && errorMsgSize > 0) { + std::string error = + "Failed to generate CMakeLists: " + generator.getLastError(); + strncpy(errorMsg, error.c_str(), errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return -1; + } + + // 编译插件 + if (!generator.compilePlugin()) { + if (errorMsg && errorMsgSize > 0) { + std::string error = "Failed to compile plugin: " + generator.getLastError(); + strncpy(errorMsg, error.c_str(), errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return -1; + } + } + + // 保存插件信息到插件管理器 + PluginManager::Instance().SetGeneratedPluginInfo(generator.getPluginInfo()); + + if (errorMsg && errorMsgSize > 0) { + strncpy(errorMsg, "Plugin generated and compiled successfully", errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return 0; + } catch (const std::exception &e) { + if (errorMsg && errorMsgSize > 0) { + strncpy(errorMsg, e.what(), errorMsgSize - 1); + errorMsg[errorMsgSize - 1] = '\0'; + } + return -1; + } +} + // 清理函数实现 void XN_Cleanup() { @@ -892,15 +989,19 @@ void XN_Cleanup() if (g_systemControlStarted) { XN_CleanupEngineControl(); } - // 停止并清理数据采集 - XN_CleanupDataCollect(); - // 停止并清理CSV数据注入 - XN_CleanupCsvDataInject(); // 停止并清理数据注入 XN_CleanupInjectContinuous(); + // 停止并清理CSV数据注入 + XN_CleanupCsvDataInject(); + // 停止并清理数据采集 + XN_CleanupDataCollect(); - // 清理DDS参与者 + // 先清理DDS参与者,再卸载插件 TopicManager::cleanupParticipant(); + + // 卸载动态加载的插件 + PluginManager::Instance().UnloadCurrentPlugin(); + g_initialized = false; } } \ No newline at end of file diff --git a/XNMonitorServer/XNMonitorInterface.h b/XNMonitorServer/XNMonitorInterface.h index e9d9c9b..5be2d21 100644 --- a/XNMonitorServer/XNMonitorInterface.h +++ b/XNMonitorServer/XNMonitorInterface.h @@ -16,12 +16,13 @@ extern "C" * @brief 初始化DDS监控服务器 * @param domainId 域ID * @param domainIdLen 域ID长度 + * @param confID 构型ID * @param errorMsg 错误信息 * @param errorMsgSize 错误信息大小 * @return 0: 成功, -1: 失败 */ - int XNMONITORSERVER_EXPORT XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, - int errorMsgSize); + int XNMONITORSERVER_EXPORT XN_Initialize(const char *domainId, int domainIdLen, int confID, + int forceGen, char *errorMsg, int errorMsgSize); /** * @brief 清理DDS监控服务器 @@ -270,6 +271,11 @@ extern "C" */ int XNMONITORSERVER_EXPORT XN_StopCollectData(char *infoMsg, int infoMsgSize); + /** + * @brief 清理所有资源 + */ + void XNMONITORSERVER_EXPORT XN_Cleanup(); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/XNMonitorServer/test/CMakeLists.txt b/XNMonitorServer/test/CMakeLists.txt new file mode 100644 index 0000000..0089fa6 --- /dev/null +++ b/XNMonitorServer/test/CMakeLists.txt @@ -0,0 +1,56 @@ +# 测试程序的CMakeLists.txt +cmake_minimum_required(VERSION 3.10) + +# 设置项目名称 +project(XNMonitorServer_Test) + +# 设置C++标准 +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 查找必要的包 +find_package(PkgConfig REQUIRED) +find_package(FastDDS REQUIRED) + +# 设置XNCore路径 +if(DEFINED ENV{XNCore}) + set(XNCore_PATH $ENV{XNCore}) +else() + message(FATAL_ERROR "Environment variable XNCore is not set.") +endif() + +# 包含目录 +include_directories( + ${CMAKE_SOURCE_DIR} + ${XNCore_PATH}/include +) + +# 创建测试可执行文件 +add_executable(test_initialize test_initialize.cpp) + +# 链接库 +target_link_libraries(test_initialize + fastcdr + fastdds + OpenSSL::SSL + OpenSSL::Crypto + pthread + dl + ${XNCore_PATH}/lib/libXNMonitorServer.so +) + +# 链接主项目的库(如果存在) +if(TARGET XNMonitorServer) + target_link_libraries(test_initialize XNMonitorServer) +endif() + +# 设置运行时库路径 +set_target_properties(test_initialize PROPERTIES + INSTALL_RPATH "${XNCore_PATH}/lib" + BUILD_WITH_INSTALL_RPATH TRUE +) + +# 安装目标 +install(TARGETS test_initialize + RUNTIME DESTINATION bin +) \ No newline at end of file diff --git a/XNMonitorServer/test/test_initialize.cpp b/XNMonitorServer/test/test_initialize.cpp new file mode 100644 index 0000000..5740ac4 --- /dev/null +++ b/XNMonitorServer/test/test_initialize.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include "../XNMonitorInterface.h" + +int main() +{ + std::cout << "=== XNMonitorServer 初始化测试 ===" << std::endl; + + // 测试参数 + const char *domainId = "10"; + int domainIdLen = strlen(domainId); + int confID = 1; + int forceGen = 0; + + char errorMsg[1024]; + int errorMsgSize = sizeof(errorMsg); + + std::cout << "测试参数:" << std::endl; + std::cout << " domainId: " << domainId << std::endl; + std::cout << " confID: " << confID << std::endl; + std::cout << " forceGen: " << forceGen << std::endl; + std::cout << std::endl; + + // 调用XN_Initialize + std::cout << "正在调用 XN_Initialize..." << std::endl; + int result = XN_Initialize(domainId, domainIdLen, confID, forceGen, errorMsg, errorMsgSize); + + if (result == 0) { + std::cout << "✓ XN_Initialize 调用成功!" << std::endl; + std::cout << "返回信息: " << errorMsg << std::endl; + + // 测试其他功能 + std::cout << std::endl << "=== 测试其他功能 ===" << std::endl; + + // 测试系统信息监控 + std::cout << "正在启动系统信息监控..." << std::endl; + int sysResult = XN_StartMonitorSystemInfo(errorMsg, errorMsgSize); + if (sysResult == 0) { + std::cout << "✓ 系统信息监控启动成功" << std::endl; + + // 获取系统信息 + char sysInfo[2048]; + int sysInfoSize = sizeof(sysInfo); + int getSysResult = XN_GetSystemInfo(sysInfo, sysInfoSize); + if (getSysResult == 0) { + std::cout << "✓ 获取系统信息成功" << std::endl; + std::cout << "系统信息: " << sysInfo << std::endl; + } else { + std::cout << "✗ 获取系统信息失败: " << sysInfo << std::endl; + } + + // 停止系统信息监控 + XN_StopMonitorSystemInfo(); + std::cout << "✓ 系统信息监控已停止" << std::endl; + } else { + std::cout << "✗ 系统信息监控启动失败: " << errorMsg << std::endl; + } + + // 测试模型信息监控 + std::cout << std::endl << "正在启动模型信息监控..." << std::endl; + int modelResult = XN_StartMonitorModelInfo(errorMsg, errorMsgSize); + if (modelResult == 0) { + std::cout << "✓ 模型信息监控启动成功" << std::endl; + + // 获取模型信息 + char modelInfo[2048]; + int modelInfoSize = sizeof(modelInfo); + int getModelResult = XN_GetModelInfo(modelInfo, modelInfoSize); + if (getModelResult == 0) { + std::cout << "✓ 获取模型信息成功" << std::endl; + std::cout << "模型信息: " << modelInfo << std::endl; + } else { + std::cout << "✗ 获取模型信息失败: " << modelInfo << std::endl; + } + + // 停止模型信息监控 + XN_StopMonitorModelInfo(); + std::cout << "✓ 模型信息监控已停止" << std::endl; + } else { + std::cout << "✗ 模型信息监控启动失败: " << errorMsg << std::endl; + } + + // 清理资源 + std::cout << std::endl << "=== 清理资源 ===" << std::endl; + XN_Cleanup(); + std::cout << "✓ 资源清理完成" << std::endl; + + } else { + std::cout << "✗ XN_Initialize 调用失败!" << std::endl; + std::cout << "错误信息: " << errorMsg << std::endl; + } + + std::cout << std::endl << "=== 测试完成 ===" << std::endl; + return result; +} \ No newline at end of file diff --git a/XNSimPortal/components/run-sim.js b/XNSimPortal/components/run-sim.js index 87be1c2..96b01fa 100644 --- a/XNSimPortal/components/run-sim.js +++ b/XNSimPortal/components/run-sim.js @@ -341,7 +341,8 @@ class RunSim extends HTMLElement { 'Content-Type': 'application/json' }, body: JSON.stringify({ - domainId: domainId, + domainId: domainId, + confID: confID }) }); @@ -569,7 +570,11 @@ class RunSim extends HTMLElement { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ domainId }) + body: JSON.stringify({ + domainId: domainId, + confID: confID, + forceGen : 1 + }) }); if (!ddsInitResponse.ok) { diff --git a/XNSimPortal/routes/DDSMonitor.js b/XNSimPortal/routes/DDSMonitor.js index 3fa3cf8..b69c589 100644 --- a/XNSimPortal/routes/DDSMonitor.js +++ b/XNSimPortal/routes/DDSMonitor.js @@ -6,22 +6,24 @@ const { initializeMonitor, cleanupMonitor } = require('../utils/xnCoreService'); let monitorStatus = { isInitialized: false, domainId: null, + confID: null, + forceGen: 0, lastError: null }; // 初始化监控服务 router.post('/initialize', async (req, res) => { try { - const { domainId } = req.body; + const { domainId, confID, forceGen = 0 } = req.body; - if (!domainId) { - return res.status(400).json({ error: '缺少必要的参数' }); + if (!domainId || confID === undefined) { + return res.status(400).json({ error: '缺少必要的参数: domainId 和 confID' }); } - // 如果已经初始化,检查域ID是否匹配 + // 如果已经初始化,检查域ID和配置ID是否匹配 if (monitorStatus.isInitialized) { - if (monitorStatus.domainId !== domainId) { - return res.status(400).json({ error: 'DDS域ID不匹配' }); + if (monitorStatus.domainId !== domainId || monitorStatus.confID !== confID) { + return res.status(400).json({ error: 'DDS域ID或配置ID不匹配' }); } return res.json({ message: '监控服务已初始化', @@ -30,7 +32,7 @@ router.post('/initialize', async (req, res) => { } // 首次初始化 - const result = initializeMonitor(domainId); + const result = initializeMonitor(domainId, confID, forceGen); if (result && result.includes('失败')) { monitorStatus.lastError = result; return res.status(500).json({ error: result }); @@ -38,6 +40,8 @@ router.post('/initialize', async (req, res) => { monitorStatus.isInitialized = true; monitorStatus.domainId = domainId; + monitorStatus.confID = confID; + monitorStatus.forceGen = forceGen; monitorStatus.lastError = null; res.json({ @@ -59,6 +63,8 @@ router.post('/unregister', async (req, res) => { monitorStatus = { isInitialized: false, domainId: null, + confID: null, + forceGen: 0, lastError: null }; diff --git a/XNSimPortal/utils/xnCoreService.js b/XNSimPortal/utils/xnCoreService.js index 48221ac..3bfe521 100644 --- a/XNSimPortal/utils/xnCoreService.js +++ b/XNSimPortal/utils/xnCoreService.js @@ -58,7 +58,7 @@ try { try { monitorLib = ffi.Library(monitorLibPath, { - 'XN_Initialize': ['int', [StringType, 'int', StringType, 'int']], + 'XN_Initialize': ['int', [StringType, 'int', 'int', 'int', StringType, 'int']], 'XN_Cleanup': ['void', []], 'XN_StartMonitorSystemInfo': ['int', [StringType, 'int']], 'XN_GetSystemInfo': ['int', [StringType, 'int']], @@ -156,14 +156,14 @@ function stringToBuffer(str) { } // 初始化监控服务器 -function initializeMonitor(domainId) { +function initializeMonitor(domainId, confID, forceGen = 0) { if (!monitorLib) { return '监控服务器库未加载'; } try { // 创建错误消息缓冲区 const errorMsg = Buffer.alloc(1024); - const result = monitorLib.XN_Initialize(domainId, domainId.length, errorMsg, errorMsg.length); + const result = monitorLib.XN_Initialize(domainId, domainId.length, confID, forceGen, errorMsg, errorMsg.length); if (result !== 0) { return `初始化失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;