V0.34.0.250624_alpha:更改了监控后端C++服务

This commit is contained in:
jinchao 2025-06-24 16:07:07 +08:00
parent 63442f0e27
commit a78e1bb85f
60 changed files with 3301 additions and 163 deletions

View File

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

View File

@ -0,0 +1,319 @@
#include "XNGroundHandling.h"
#include "XNGroundHandling_p.h"
#include <XNCore/XNModelManager.h>
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;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "XNGroundHandling_global.h"
#include <XNCore/XNModelObject.h>
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)

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Name>XNGroundHandling</Name>
<Description>ATA04GroundHandling</Description>
<Author>Jin</Author>
<Version>2.0.143.1</Version>
<CreateTime>2025-04-03 14:47:42</CreateTime>
<ChangeTime>2025-04-03 14:47:42</ChangeTime>
<Node>0</Node>
<Priority>99</Priority>
<MathLib>ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H</MathLib>
<CommandList/>
</Model>

View File

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

View File

@ -0,0 +1,19 @@
#pragma once
#include <XNCore/XNModelObject_p.h>
#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;
};

View File

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

View File

@ -0,0 +1,106 @@
#include "XNWeightBalance.h"
#include "XNWeightBalance_p.h"
#include <XNCore/XNModelManager.h>
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;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "XNWeightBalance_global.h"
#include <XNCore/XNModelObject.h>
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)

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Name>XNWeightBalance</Name>
<Description>ATA04WeightBalance</Description>
<Author>Jin</Author>
<Version>2.0.14.6</Version>
<CreateTime>2025-04-27 13:57:50</CreateTime>
<ChangeTime>2025-04-27 13:57:50</ChangeTime>
<Node>0</Node>
<Priority>99</Priority>
<MathLib>ATA04_WeightBalance_2.0.14.6H_20241106/libSACSCWeightBalance.so</MathLib>
<CommandList/>
</Model>

View File

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

View File

@ -0,0 +1,19 @@
#pragma once
#include <XNCore/XNModelObject_p.h>
#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;
};

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Name>XNGroundHandling</Name>
<Description>ATA04地面操纵模型</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-19 16:22:17</CreateTime>
<ChangeTime>2025-02-19 16:22:19</ChangeTime>
<Node>0-0</Node>
<Priority>99</Priority>
<MathLib>ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H</MathLib>
<CommandList/>
</Model>

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Name>XNGroundHandling</Name>
<Description>ATA04地面操纵模型</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-19 16:22:17</CreateTime>
<ChangeTime>2025-02-19 16:22:19</ChangeTime>
<Node>0-0</Node>
<Priority>99</Priority>
<MathLib>ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H</MathLib>
<CommandList/>
<Name>XNGroundHandling</Name>
<Description>ATA04GroundHandling</Description>
<Author>Jin</Author>
<Version>2.0.143.1</Version>
<CreateTime>2025-04-03 14:47:42</CreateTime>
<ChangeTime>2025-04-03 14:47:42</ChangeTime>
<Node>0</Node>
<Priority>99</Priority>
<MathLib>ATA04_SACSCGroundHandling_2.0.143.1H_20250506/libSACSCGroundHandling.so.2.0.143.1H</MathLib>
<CommandList/>
</Model>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Name>XNWeightBalance</Name>
<Description>ATA04质量模型</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-20 09:29:18</CreateTime>
<ChangeTime>2025-02-20 09:29:20</ChangeTime>
<Node>0-0</Node>
<Priority>99</Priority>
<MathLib>ATA04_WeightBalance_2.0.14.6H_20241106/libSACSCWeightBalance.so</MathLib>
<CommandList/>
</Model>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Model>
<Name>XNWeightBalance</Name>
<Description>ATA04WeightBalance</Description>
<Author>Jin</Author>
<Version>2.0.14.6</Version>
<CreateTime>2025-04-27 13:57:50</CreateTime>
<ChangeTime>2025-04-27 13:57:50</ChangeTime>
<Node>0</Node>
<Priority>99</Priority>
<MathLib>ATA04_WeightBalance_2.0.14.6H_20241106/libSACSCWeightBalance.so</MathLib>
<CommandList/>
</Model>

View File

@ -0,0 +1,84 @@
#include <XNMonitor/PluginInterface.h>
#include <XNMonitor/DataMonitor.h>
// 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<DataMonitorProduct<XNSim::C909::ATA04::Aerodynamics_input_Interface>>();
} else
if (name == "GroundHandling_input") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::GroundHandling_input_Interface>>();
} else
if (name == "GroundHandling_output") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::GroundHandling_output_Interface>>();
} else
if (name == "Aerodynamics_output") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::Aerodynamics_output_Interface>>();
} else
if (name == "WeightBalance_input") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::WeightBalance_input_Interface>>();
} else
if (name == "WeightBalance_output") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::WeightBalance_output_Interface>>();
} else
if (name == "GroundHandling_heartbeat") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::GroundHandling_heartbeat_Interface>>();
} else
if (name == "WeightBalance_heartbeat") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::WeightBalance_heartbeat_Interface>>();
} else
if (name == "Aerodynamics_heartbeat") {
return std::make_shared<DataMonitorProduct<XNSim::C909::ATA04::Aerodynamics_heartbeat_Interface>>();
}
return nullptr;
}
void destroy_monitor(const char *interfaceName)
{
// 智能指针会自动管理内存,这里可以添加额外的清理逻辑
}
const char **get_supported_interfaces(int *count)
{
if (count) {
*count = interface_count;
}
return const_cast<const char **>(supported_interfaces);
}
void free_string_array(const char **array)
{
// 这里不需要释放,因为使用的是静态数组
}
}

View File

@ -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 .
)

Binary file not shown.

View File

@ -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<MonitorDataInfo> 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<MonitorDataInfo> m_injectDataInfos;
std::vector<CSVHeaderField> m_headerFields;
std::thread m_thread; ///< 数据注入线程
std::atomic<bool> m_running; ///< 线程运行标志
std::mutex m_mutex; ///< 互斥锁
std::condition_variable m_cv; ///< 条件变量
std::unordered_map<std::string, DataMonitorBasePtr>
m_alreadyStartedMonitors; ///< 已经启动的数据监控器
std::unordered_map<std::string, DataMonitorBasePtr>
m_notStartedMonitors; ///< 未启动的数据监控器
std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
m_data; ///< 要注入的数据
std::atomic<int64_t> m_nextExecuteTime; ///< 下一次执行的时间点
};

View File

@ -0,0 +1,52 @@
#pragma once
#include "DataMonitor.h"
class DataCollect
{
public:
DataCollect();
~DataCollect();
public:
bool Initialize(std::vector<MonitorDataInfo> 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<MonitorDataInfo> m_collectDataInfos;
std::vector<CSVHeaderField> m_headerFields;
std::thread m_thread; ///< 数据采集线程
std::atomic<bool> m_running; ///< 线程运行标志
std::mutex m_mutex; ///< 互斥锁
std::condition_variable m_cv; ///< 条件变量
std::unordered_map<std::string, DataMonitorBasePtr>
m_alreadyStartedMonitors; ///< 已经启动的数据监控器
std::unordered_map<std::string, DataMonitorBasePtr>
m_notStartedMonitors; ///< 未启动的数据监控器
std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
m_data; ///< 采集到的数据
std::atomic<int64_t> m_nextExecuteTime; ///< 下一次执行的时间点
int m_collectDuration; ///< 采集时长(秒)
int m_collectFrequency; ///< 采集频率Hz
};

View File

@ -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<std::string, std::string> data, double frequency);
/**
* @brief
*/
~DataInjectThread();
/**
* @brief 线
*/
void start();
/**
* @brief 线
*/
void stop();
/**
* @brief
* @param data
*/
void updateData(const std::unordered_map<std::string, std::string> &data);
/**
* @brief
* @param frequency (Hz)
*/
void updateFrequency(double frequency);
private:
/**
* @brief 线
*/
void threadFunc();
private:
std::thread m_thread; ///< 数据注入线程
std::atomic<bool> m_running; ///< 线程运行标志
std::mutex m_mutex; ///< 互斥锁
std::condition_variable m_cv; ///< 条件变量
DataMonitorBasePtr m_dataMonitor; ///< 数据监控器指针
std::unordered_map<std::string, std::string> m_data; ///< 要注入的数据
std::atomic<double> m_frequency; ///< 注入频率
};
using DataInjectThreadPtr = std::shared_ptr<DataInjectThread>;

View File

@ -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<XNFramework>;
class XNMONITORSERVER_EXPORT DataMonitorBase
{
public:
virtual void Initialize(XNFrameworkPtr framework, uint32_t modelId, uint32_t DDS_type) = 0;
virtual std::unordered_map<std::string, std::string>
getStringData(std::vector<std::string> varNames) = 0;
virtual void setDataByString(std::unordered_map<std::string, std::string> data) = 0;
virtual bool isInitialized() { return _isInitialized; }
protected:
bool _isInitialized = false;
};
template <typename T>
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<typename T::DDSPubSubType>(
T::topic_name,
std::bind(&DataMonitorProduct::inputDataListener, this, std::placeholders::_1));
if (ret != XNDDSErrorCode::SUCCESS) {
return;
}
ret = TopicManager::Instance()->registerPublisher<typename T::DDSPubSubType>(
T::topic_name, this->dataWriter);
if (ret != XNDDSErrorCode::SUCCESS || this->dataWriter == nullptr) {
return;
}
_isInitialized = true;
};
virtual std::unordered_map<std::string, std::string>
getStringData(std::vector<std::string> varNames) override
{
if (!isInitialized()) {
return {};
}
return T::getStringData(varNames);
}
virtual void setDataByString(std::unordered_map<std::string, std::string> data) override
{
if (!isInitialized()) {
return;
}
T::setDataByString(data);
}
};
using DataMonitorBasePtr = std::shared_ptr<DataMonitorBase>;

View File

@ -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<std::string> GetRegisteredInterfaces();
private:
DataMonitorFactory() = delete;
~DataMonitorFactory() = delete;
};

View File

@ -0,0 +1,37 @@
#pragma once
#include "TopicManager.h"
#include <XNIDL/XNSimStatusPubSubTypes.hpp>
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<uint32_t, XNSim::XNSimStatus::XNModelStatus> m_ModelStatus;
/**
* @brief
*/
std::map<uint32_t, uint64_t> m_ModelCycleCount;
};

View File

@ -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<InterfaceInfo> 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;
};

View File

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

View File

@ -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<std::string> 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<std::string, DataMonitorBasePtr> m_monitorCache;
};

View File

@ -0,0 +1,24 @@
#pragma once
#include "XNMonitorServer_global.h"
#include "TypeDefine.h"
#include "TopicManager.h"
#include <XNIDL/XNSimStatusPubSubTypes.hpp>
class XNMONITORSERVER_EXPORT SystemControl
{
public:
SystemControl() {};
virtual ~SystemControl();
public:
std::string Initialize();
void Pause();
void Resume();
void Stop();
void cleanup();
private:
XNDataWriter *m_EngineControlWriter;
};

View File

@ -0,0 +1,52 @@
#pragma once
#include "TopicManager.h"
#include <XNIDL/XNSimStatusPubSubTypes.hpp>
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<uint32_t, XNSim::XNSimStatus::XNThreadStatus> m_ThreadStatus;
/**
* @brief 线
*/
std::map<uint32_t, uint64_t> m_ThreadCycleCount;
};

View File

@ -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<std::mutex> locker(instanceMutex);
if (instance == nullptr) { // 双重检查锁定
instance = new TopicManager();
}
}
return instance;
}
/**
* @brief
*/
static void cleanupParticipant()
{
std::lock_guard<std::mutex> 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 <typename T>
XNDDSErrorCode registerPublisher(const std::string &topicName, XNDataWriter *&dataWriter)
{
std::lock_guard<std::mutex> 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<std::mutex> 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 <typename T>
XNDDSErrorCode registerSubscriber(const std::string &topicName,
std::function<void(const typename T::type &)> fun)
{
std::lock_guard<std::mutex> 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<typename T::type>(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<typename T::type>(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<std::mutex> 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<std::mutex> 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<std::string, MonitorTopicInfo> topics_;
/**
* @brief 访
*/
std::mutex m_Mutex;
};

View File

@ -0,0 +1,270 @@
/**
* @file TypeDefine.h
* @brief
*/
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <map>
#include <mutex>
#include <nlohmann/json.hpp>
#include <iostream>
#include <unordered_map>
#include <typeindex>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <fstream>
#include <filesystem>
#include <dlfcn.h>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <sqlite3.h>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>
#include <fastdds/dds/subscriber/DataReaderListener.hpp>
#include <fastdds/dds/subscriber/DataReader.hpp>
#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>
#include <fastdds/dds/subscriber/SampleInfo.hpp>
#include <fastdds/dds/subscriber/Subscriber.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>
#include <fastdds/dds/topic/Topic.hpp>
#include <fastdds/dds/topic/TopicDataType.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/publisher/qos/PublisherQos.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
#include <fastdds/dds/core/status/StatusMask.hpp>
/**
* @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<int> arraySizes;
/**
* @brief
*/
std::string description;
};
/**
* @brief
* @note
*/
struct StructDefinition {
/**
* @brief
*/
std::string structName;
/**
* @brief
*/
std::vector<std::shared_ptr<MemberVariable>> memberVariables;
};
/**
* @brief
* @note
*/
struct NamespaceDefinition {
/**
* @brief
*/
std::string namespaceName;
/**
* @brief
*/
std::vector<std::shared_ptr<StructDefinition>> structDefinitions;
/**
* @brief
*/
std::vector<std::shared_ptr<NamespaceDefinition>> childNamespaces;
};
/**
* @brief
* @note
*/
struct ModelDefinition {
/**
* @brief
*/
std::string modelName;
/**
* @brief
*/
std::vector<std::shared_ptr<NamespaceDefinition>> namespaceDefinitions;
};
struct MonitorDataInfo {
/**
* @brief
*/
std::string structName;
/**
* @brief
*/
std::vector<std::string> interfaceNames;
/**
* @brief
*/
std::vector<std::pair<int, int>> 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;
};

View File

@ -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 <typename T>
class XNDataReaderListenerImpl : public XNDataReaderListener
{
public:
/**
* @brief
* @param callback
*/
XNDataReaderListenerImpl(std::function<void(const T &)> 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<void(const T &)> callback_;
};

View File

@ -0,0 +1,281 @@
/**
* @file XNMonitorInterface.h
* @brief
*/
#pragma once
#include "TypeDefine.h"
#include "XNMonitorServer_global.h"
#include <cstdint>
#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

View File

@ -0,0 +1,7 @@
#pragma once
#ifdef XNMonitorServer_EXPORTS
# define XNMONITORSERVER_EXPORT __attribute__((visibility("default")))
#else
# define XNMONITORSERVER_EXPORT __attribute__((visibility("default")))
#endif

View File

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

View File

@ -73,6 +73,7 @@
"any": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"valarray": "cpp"
"valarray": "cpp",
"*.ipp": "cpp"
}
}

View File

@ -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)

View File

@ -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<std::type_index, DataMonitorBasePtr> DataMonitorFactory::instances_;
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<std::string> DataMonitorFactory::GetRegisteredInterfaces()
{
return PluginManager::Instance().GetSupportedInterfaces();
}

View File

@ -3,108 +3,23 @@
#include "XNMonitorServer_global.h"
#include "DataMonitor.h"
//接口头文件
#include <IDL/C909_V1_Interface.h>
/**
* @brief DataMonitor工厂类DataMonitor实例
*/
class XNMONITORSERVER_EXPORT DataMonitorFactory
{
public:
static DataMonitorBasePtr GetInstance(const std::string &interfaceName)
{
if (interfaceName == "Aerodynamics_heartbeat") {
return GetInstance<XNSim::C909::ATA04::Aerodynamics_heartbeat_Interface>();
} else if (interfaceName == "Aerodynamics_input") {
return GetInstance<XNSim::C909::ATA04::Aerodynamics_input_Interface>();
} else if (interfaceName == "Aerodynamics_output") {
return GetInstance<XNSim::C909::ATA04::Aerodynamics_output_Interface>();
} else if (interfaceName == "GroundHandling_heartbeat") {
return GetInstance<XNSim::C909::ATA04::GroundHandling_heartbeat_Interface>();
} else if (interfaceName == "GroundHandling_input") {
return GetInstance<XNSim::C909::ATA04::GroundHandling_input_Interface>();
} else if (interfaceName == "GroundHandling_output") {
return GetInstance<XNSim::C909::ATA04::GroundHandling_output_Interface>();
} else if (interfaceName == "WeightBalance_heartbeat") {
return GetInstance<XNSim::C909::ATA04::WeightBalance_heartbeat_Interface>();
} else if (interfaceName == "WeightBalance_input") {
return GetInstance<XNSim::C909::ATA04::WeightBalance_input_Interface>();
} else if (interfaceName == "WeightBalance_output") {
return GetInstance<XNSim::C909::ATA04::WeightBalance_output_Interface>();
}
return nullptr;
}
static DataMonitorBasePtr GetInstance(const std::string &interfaceName);
static void ReleaseInstance(const std::string &interfaceName)
{
if (interfaceName == "Aerodynamics_heartbeat") {
ReleaseInstance<XNSim::C909::ATA04::Aerodynamics_heartbeat_Interface>();
} else if (interfaceName == "Aerodynamics_input") {
ReleaseInstance<XNSim::C909::ATA04::Aerodynamics_input_Interface>();
} else if (interfaceName == "Aerodynamics_output") {
ReleaseInstance<XNSim::C909::ATA04::Aerodynamics_output_Interface>();
} else if (interfaceName == "GroundHandling_heartbeat") {
ReleaseInstance<XNSim::C909::ATA04::GroundHandling_heartbeat_Interface>();
} else if (interfaceName == "GroundHandling_input") {
ReleaseInstance<XNSim::C909::ATA04::GroundHandling_input_Interface>();
} else if (interfaceName == "GroundHandling_output") {
ReleaseInstance<XNSim::C909::ATA04::GroundHandling_output_Interface>();
} else if (interfaceName == "WeightBalance_heartbeat") {
ReleaseInstance<XNSim::C909::ATA04::WeightBalance_heartbeat_Interface>();
} else if (interfaceName == "WeightBalance_input") {
ReleaseInstance<XNSim::C909::ATA04::WeightBalance_input_Interface>();
} else if (interfaceName == "WeightBalance_output") {
ReleaseInstance<XNSim::C909::ATA04::WeightBalance_output_Interface>();
}
}
static void ReleaseInstance(const std::string &interfaceName);
private:
/**
* @brief DataMonitor实例
* @param framework
* @param modelId ID
* @param DDS_type DDS类型
* @return DataMonitor实例的智能指针
*/
template <typename T>
static DataMonitorBasePtr GetInstance()
{
std::lock_guard<std::mutex> 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<DataMonitorProduct<T>>();
instances_[typeIndex] = monitor;
return monitor;
}
/**
* @brief
*/
template <typename T>
static void ReleaseInstance()
{
std::lock_guard<std::mutex> lock(mutex_);
std::type_index typeIndex(typeid(T));
if (instances_.find(typeIndex) == instances_.end()) {
return;
}
instances_.erase(typeIndex);
}
// 获取所有已注册的接口名称
static std::vector<std::string> GetRegisteredInterfaces();
private:
DataMonitorFactory() = delete;
~DataMonitorFactory() = delete;
static std::mutex mutex_;
static std::unordered_map<std::type_index, DataMonitorBasePtr> instances_;
};

View File

@ -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<const char *>(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<const char *>(sqlite3_column_text(dataInterfaceStmt, 0));
std::string systemName =
reinterpret_cast<const char *>(sqlite3_column_text(dataInterfaceStmt, 1));
std::string planeName =
reinterpret_cast<const char *>(sqlite3_column_text(dataInterfaceStmt, 2));
std::string ataName =
reinterpret_cast<const char *>(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 <XNMonitor/PluginInterface.h>\n";
ss << "#include <XNMonitor/DataMonitor.h>\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<DataMonitorProduct<" << interface.templateType
<< ">>();\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<const char **>(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;
}

View File

@ -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<InterfaceInfo> 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;
};

View File

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

View File

@ -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<GetPluginInfoFunc>(dlsym(m_pluginHandle, "get_plugin_info"));
m_createMonitorFunc =
reinterpret_cast<CreateMonitorFunc>(dlsym(m_pluginHandle, "create_monitor"));
m_destroyMonitorFunc =
reinterpret_cast<DestroyMonitorFunc>(dlsym(m_pluginHandle, "destroy_monitor"));
m_getSupportedInterfacesFunc = reinterpret_cast<GetSupportedInterfacesFunc>(
dlsym(m_pluginHandle, "get_supported_interfaces"));
m_freeStringArrayFunc =
reinterpret_cast<FreeStringArrayFunc>(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<std::string> PluginManager::GetSupportedInterfaces()
{
std::vector<std::string> 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;
}

View File

@ -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<std::string> 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<std::string, DataMonitorBasePtr> m_monitorCache;
};

View File

@ -1,5 +1,5 @@
#include "SystemControl.h"
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
#include "XNIDL/XNSimStatusPubSubTypes.hpp"
SystemControl::~SystemControl()
{

View File

@ -16,6 +16,13 @@
#include <atomic>
#include <condition_variable>
#include <fstream>
#include <filesystem>
#include <dlfcn.h>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <sqlite3.h>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>

View File

@ -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<std::string, DataInjectThreadPtr> 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;
}
}

View File

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

View File

@ -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
)

View File

@ -0,0 +1,96 @@
#include <iostream>
#include <string>
#include <cstring>
#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;
}

View File

@ -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) {

View File

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

View File

@ -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, '')}`;