V0.34.0.250624_alpha:更改了监控后端C++服务
This commit is contained in:
parent
63442f0e27
commit
a78e1bb85f
Binary file not shown.
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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>
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
Binary file not shown.
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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>
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
84
Release/Configuration/C909_V1/PluginCode/C909_V1_plugin.cpp
Normal file
84
Release/Configuration/C909_V1/PluginCode/C909_V1_plugin.cpp
Normal 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)
|
||||
{
|
||||
// 这里不需要释放,因为使用的是静态数组
|
||||
}
|
||||
}
|
44
Release/Configuration/C909_V1/PluginCode/CMakeLists.txt
Normal file
44
Release/Configuration/C909_V1/PluginCode/CMakeLists.txt
Normal 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.
66
Release/include/XNMonitor/CSVDataInjectThread.h
Normal file
66
Release/include/XNMonitor/CSVDataInjectThread.h
Normal 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; ///< 下一次执行的时间点
|
||||
};
|
52
Release/include/XNMonitor/DataCollect.h
Normal file
52
Release/include/XNMonitor/DataCollect.h
Normal 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)
|
||||
};
|
63
Release/include/XNMonitor/DataInjectThread.h
Normal file
63
Release/include/XNMonitor/DataInjectThread.h
Normal 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>;
|
80
Release/include/XNMonitor/DataMonitor.h
Normal file
80
Release/include/XNMonitor/DataMonitor.h
Normal 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>;
|
25
Release/include/XNMonitor/DataMonitorFactory.h
Normal file
25
Release/include/XNMonitor/DataMonitorFactory.h
Normal 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;
|
||||
};
|
37
Release/include/XNMonitor/ModelInfoMonitor.h
Normal file
37
Release/include/XNMonitor/ModelInfoMonitor.h
Normal 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;
|
||||
};
|
66
Release/include/XNMonitor/PluginGenerator.h
Normal file
66
Release/include/XNMonitor/PluginGenerator.h
Normal 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;
|
||||
};
|
34
Release/include/XNMonitor/PluginInterface.h
Normal file
34
Release/include/XNMonitor/PluginInterface.h
Normal 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"
|
51
Release/include/XNMonitor/PluginManager.h
Normal file
51
Release/include/XNMonitor/PluginManager.h
Normal 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;
|
||||
};
|
24
Release/include/XNMonitor/SystemControl.h
Normal file
24
Release/include/XNMonitor/SystemControl.h
Normal 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;
|
||||
};
|
52
Release/include/XNMonitor/SystemInfoMonitor.h
Normal file
52
Release/include/XNMonitor/SystemInfoMonitor.h
Normal 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;
|
||||
};
|
310
Release/include/XNMonitor/TopicManager.h
Normal file
310
Release/include/XNMonitor/TopicManager.h
Normal 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;
|
||||
};
|
270
Release/include/XNMonitor/TypeDefine.h
Normal file
270
Release/include/XNMonitor/TypeDefine.h
Normal 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;
|
||||
};
|
51
Release/include/XNMonitor/XNDataReaderListenerImpl.h
Normal file
51
Release/include/XNMonitor/XNDataReaderListenerImpl.h
Normal 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_;
|
||||
};
|
281
Release/include/XNMonitor/XNMonitorInterface.h
Normal file
281
Release/include/XNMonitor/XNMonitorInterface.h
Normal 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
|
7
Release/include/XNMonitor/XNMonitorServer_global.h
Normal file
7
Release/include/XNMonitor/XNMonitorServer_global.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef XNMonitorServer_EXPORTS
|
||||
# define XNMONITORSERVER_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
# define XNMONITORSERVER_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
@ -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;"
|
||||
|
3
XNMonitorServer/.vscode/settings.json
vendored
3
XNMonitorServer/.vscode/settings.json
vendored
@ -73,6 +73,7 @@
|
||||
"any": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"fstream": "cpp",
|
||||
"valarray": "cpp"
|
||||
"valarray": "cpp",
|
||||
"*.ipp": "cpp"
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
@ -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_;
|
||||
};
|
||||
|
379
XNMonitorServer/PluginGenerator.cpp
Normal file
379
XNMonitorServer/PluginGenerator.cpp
Normal 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;
|
||||
}
|
66
XNMonitorServer/PluginGenerator.h
Normal file
66
XNMonitorServer/PluginGenerator.h
Normal 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;
|
||||
};
|
34
XNMonitorServer/PluginInterface.h
Normal file
34
XNMonitorServer/PluginInterface.h
Normal 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"
|
126
XNMonitorServer/PluginManager.cpp
Normal file
126
XNMonitorServer/PluginManager.cpp
Normal 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;
|
||||
}
|
51
XNMonitorServer/PluginManager.h
Normal file
51
XNMonitorServer/PluginManager.h
Normal 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;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
#include "SystemControl.h"
|
||||
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
||||
#include "XNIDL/XNSimStatusPubSubTypes.hpp"
|
||||
|
||||
SystemControl::~SystemControl()
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
56
XNMonitorServer/test/CMakeLists.txt
Normal file
56
XNMonitorServer/test/CMakeLists.txt
Normal 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
|
||||
)
|
96
XNMonitorServer/test/test_initialize.cpp
Normal file
96
XNMonitorServer/test/test_initialize.cpp
Normal 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;
|
||||
}
|
@ -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) {
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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, '')}`;
|
||||
|
Loading…
x
Reference in New Issue
Block a user