增加了引擎的暂停与结束控制
This commit is contained in:
parent
0296daa268
commit
04767fe971
Binary file not shown.
@ -37,6 +37,8 @@ add_library(XNMonitorServer SHARED
|
|||||||
SystemInfoMonitor.cpp
|
SystemInfoMonitor.cpp
|
||||||
ModelInfoMonitor.h
|
ModelInfoMonitor.h
|
||||||
ModelInfoMonitor.cpp
|
ModelInfoMonitor.cpp
|
||||||
|
SystemControl.h
|
||||||
|
SystemControl.cpp
|
||||||
${DDS_XNIDL_SOURCES_CXX}
|
${DDS_XNIDL_SOURCES_CXX}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
#include "ModelInfoMonitor.h"
|
#include "ModelInfoMonitor.h"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
ModelInfoMonitor::~ModelInfoMonitor()
|
ModelInfoMonitor::~ModelInfoMonitor()
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "XNMonitorServer_global.h"
|
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
|
||||||
#include "TypeDefine.h"
|
|
||||||
#include "TopicManager.h"
|
#include "TopicManager.h"
|
||||||
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
||||||
|
|
||||||
|
58
XNMonitorServer/SystemControl.cpp
Normal file
58
XNMonitorServer/SystemControl.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "SystemControl.h"
|
||||||
|
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
||||||
|
|
||||||
|
SystemControl::~SystemControl()
|
||||||
|
{
|
||||||
|
//注销引擎控制发布者
|
||||||
|
TopicManager::Instance()->unregisterPublisher("XNSim::XNSimControl::XNRuntimeControl");
|
||||||
|
m_EngineControlWriter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SystemControl::Initialize()
|
||||||
|
{
|
||||||
|
m_EngineControlWriter = nullptr;
|
||||||
|
XNDDSErrorCode ret = TopicManager::Instance()
|
||||||
|
->registerPublisher<XNSim::XNSimControl::XNRuntimeControlPubSubType>(
|
||||||
|
"XNSim::XNSimControl::XNRuntimeControl", m_EngineControlWriter);
|
||||||
|
if (ret != XNDDSErrorCode::SUCCESS || m_EngineControlWriter == nullptr) {
|
||||||
|
return "Failed to register engine control publisher, error code: "
|
||||||
|
+ std::to_string(static_cast<int>(ret));
|
||||||
|
}
|
||||||
|
return "Success";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl::Pause()
|
||||||
|
{
|
||||||
|
// 暂停引擎
|
||||||
|
if (m_EngineControlWriter == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XNSim::XNSimControl::XNRuntimeControl cmd;
|
||||||
|
cmd.XNSimCmd(1);
|
||||||
|
cmd.XNThrCmd(0);
|
||||||
|
m_EngineControlWriter->write(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl::Resume()
|
||||||
|
{
|
||||||
|
// 恢复引擎
|
||||||
|
if (m_EngineControlWriter == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XNSim::XNSimControl::XNRuntimeControl cmd;
|
||||||
|
cmd.XNSimCmd(2);
|
||||||
|
cmd.XNThrCmd(0);
|
||||||
|
m_EngineControlWriter->write(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControl::Stop()
|
||||||
|
{
|
||||||
|
// 停止引擎
|
||||||
|
if (m_EngineControlWriter == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XNSim::XNSimControl::XNRuntimeControl cmd;
|
||||||
|
cmd.XNSimCmd(3);
|
||||||
|
cmd.XNThrCmd(0);
|
||||||
|
m_EngineControlWriter->write(&cmd);
|
||||||
|
}
|
22
XNMonitorServer/SystemControl.h
Normal file
22
XNMonitorServer/SystemControl.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XNMonitorServer_global.h"
|
||||||
|
#include "TypeDefine.h"
|
||||||
|
#include "TopicManager.h"
|
||||||
|
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
||||||
|
|
||||||
|
class XNMONITORSERVER_EXPORT SystemControl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SystemControl() {};
|
||||||
|
virtual ~SystemControl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string Initialize();
|
||||||
|
void Pause();
|
||||||
|
void Resume();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
XNDataWriter *m_EngineControlWriter;
|
||||||
|
};
|
@ -1,7 +1,4 @@
|
|||||||
#include "SystemInfoMonitor.h"
|
#include "SystemInfoMonitor.h"
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
SystemInfoMonitor::~SystemInfoMonitor()
|
SystemInfoMonitor::~SystemInfoMonitor()
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
#ifndef SYSTEMINFOMONITOR_H
|
#pragma once
|
||||||
#define SYSTEMINFOMONITOR_H
|
|
||||||
|
|
||||||
#include "XNMonitorServer_global.h"
|
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
|
||||||
#include "TypeDefine.h"
|
|
||||||
#include "TopicManager.h"
|
#include "TopicManager.h"
|
||||||
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
#include "../XNCore/XNIDL/XNSimStatusPubSubTypes.hpp"
|
||||||
|
|
||||||
@ -55,5 +50,3 @@ private:
|
|||||||
*/
|
*/
|
||||||
std::map<uint32_t, uint64_t> m_ThreadCycleCount;
|
std::map<uint32_t, uint64_t> m_ThreadCycleCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SYSTEMINFOMONITOR_H
|
|
||||||
|
@ -10,12 +10,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include "XNMonitorServer_global.h"
|
||||||
#include <mutex>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include "DataReaderListenerImpl.h"
|
#include "DataReaderListenerImpl.h"
|
||||||
#include <fastdds/dds/core/status/StatusMask.hpp>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 主题管理类
|
* @brief 主题管理类
|
||||||
@ -101,8 +97,7 @@ public:
|
|||||||
* @return XNDataWriter*: 数据写入器
|
* @return XNDataWriter*: 数据写入器
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
XNDDSErrorCode registerPublisher(const std::string &topicName,
|
XNDDSErrorCode registerPublisher(const std::string &topicName, XNDataWriter *&dataWriter)
|
||||||
XNDataWriter *dataWriter = nullptr)
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> locker(m_Mutex);
|
std::lock_guard<std::mutex> locker(m_Mutex);
|
||||||
if (topics_.find(topicName) == topics_.end()) {
|
if (topics_.find(topicName) == topics_.end()) {
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <iostream>
|
||||||
#include <fastdds/dds/domain/DomainParticipant.hpp>
|
#include <fastdds/dds/domain/DomainParticipant.hpp>
|
||||||
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
|
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
|
||||||
#include <fastdds/dds/topic/TypeSupport.hpp>
|
#include <fastdds/dds/topic/TypeSupport.hpp>
|
||||||
@ -21,6 +25,7 @@
|
|||||||
#include <fastdds/dds/publisher/qos/PublisherQos.hpp>
|
#include <fastdds/dds/publisher/qos/PublisherQos.hpp>
|
||||||
#include <fastdds/dds/publisher/DataWriter.hpp>
|
#include <fastdds/dds/publisher/DataWriter.hpp>
|
||||||
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
|
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
|
||||||
|
#include <fastdds/dds/core/status/StatusMask.hpp>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 域参与者
|
* @brief 域参与者
|
||||||
@ -83,6 +88,7 @@ using XNTopic = eprosima::fastdds::dds::Topic;
|
|||||||
*/
|
*/
|
||||||
using XNTopicDataType = eprosima::fastdds::dds::TopicDataType;
|
using XNTopicDataType = eprosima::fastdds::dds::TopicDataType;
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
/**
|
/**
|
||||||
* @brief 主题信息
|
* @brief 主题信息
|
||||||
*/
|
*/
|
||||||
|
@ -3,11 +3,9 @@
|
|||||||
* @brief 监控服务器接口实现
|
* @brief 监控服务器接口实现
|
||||||
*/
|
*/
|
||||||
#include "XNMonitorInterface.h"
|
#include "XNMonitorInterface.h"
|
||||||
#include "TopicManager.h"
|
|
||||||
#include <string>
|
|
||||||
#include <mutex>
|
|
||||||
#include "SystemInfoMonitor.h"
|
#include "SystemInfoMonitor.h"
|
||||||
#include "ModelInfoMonitor.h"
|
#include "ModelInfoMonitor.h"
|
||||||
|
#include "SystemControl.h"
|
||||||
|
|
||||||
// 全局变量
|
// 全局变量
|
||||||
static bool g_initialized = false;
|
static bool g_initialized = false;
|
||||||
@ -16,6 +14,8 @@ SystemInfoMonitor *systemInfoMonitor = nullptr;
|
|||||||
bool g_systemInfoMonitorStarted = false;
|
bool g_systemInfoMonitorStarted = false;
|
||||||
ModelInfoMonitor *modelInfoMonitor = nullptr;
|
ModelInfoMonitor *modelInfoMonitor = nullptr;
|
||||||
bool g_modelInfoMonitorStarted = false;
|
bool g_modelInfoMonitorStarted = false;
|
||||||
|
SystemControl *systemControl = nullptr;
|
||||||
|
bool g_systemControlStarted = false;
|
||||||
|
|
||||||
// 初始化函数实现
|
// 初始化函数实现
|
||||||
int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int errorMsgSize)
|
int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int errorMsgSize)
|
||||||
@ -288,6 +288,71 @@ void XN_Cleanup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int XN_InitializeEngineControl(char *errorMsg, int errorMsgSize)
|
||||||
|
{
|
||||||
|
if (g_systemControlStarted) {
|
||||||
|
if (errorMsg && errorMsgSize > 0) {
|
||||||
|
strncpy(errorMsg, "Engine Control Already Started", errorMsgSize - 1);
|
||||||
|
errorMsg[errorMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
systemControl = new SystemControl();
|
||||||
|
std::string ret = systemControl->Initialize();
|
||||||
|
if (ret == "Success") {
|
||||||
|
g_systemControlStarted = true;
|
||||||
|
if (errorMsg && errorMsgSize > 0) {
|
||||||
|
strncpy(errorMsg, "Engine Control Initialized Successfully", errorMsgSize - 1);
|
||||||
|
errorMsg[errorMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
delete systemControl;
|
||||||
|
systemControl = nullptr;
|
||||||
|
if (errorMsg && errorMsgSize > 0) {
|
||||||
|
strncpy(errorMsg, ret.c_str(), errorMsgSize - 1);
|
||||||
|
errorMsg[errorMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XN_PauseEngine(char *errorMsg, int errorMsgSize)
|
||||||
|
{
|
||||||
|
if (!g_systemControlStarted) {
|
||||||
|
if (errorMsg && errorMsgSize > 0) {
|
||||||
|
strncpy(errorMsg, "Engine Control Not Started", errorMsgSize - 1);
|
||||||
|
errorMsg[errorMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
systemControl->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XN_ResumeEngine(char *errorMsg, int errorMsgSize)
|
||||||
|
{
|
||||||
|
if (!g_systemControlStarted) {
|
||||||
|
if (errorMsg && errorMsgSize > 0) {
|
||||||
|
strncpy(errorMsg, "Engine Control Not Started", errorMsgSize - 1);
|
||||||
|
errorMsg[errorMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
systemControl->Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XN_StopEngine(char *errorMsg, int errorMsgSize)
|
||||||
|
{
|
||||||
|
if (!g_systemControlStarted) {
|
||||||
|
if (errorMsg && errorMsgSize > 0) {
|
||||||
|
strncpy(errorMsg, "Engine Control Not Started", errorMsgSize - 1);
|
||||||
|
errorMsg[errorMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
systemControl->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
// // 注册发布者实现
|
// // 注册发布者实现
|
||||||
// XNDDSErrorCode XN_RegisterPublisher(const char *topicName, void **dataWriter)
|
// XNDDSErrorCode XN_RegisterPublisher(const char *topicName, void **dataWriter)
|
||||||
// {
|
// {
|
||||||
|
@ -40,6 +40,18 @@ extern "C"
|
|||||||
// 停止监控模型信息
|
// 停止监控模型信息
|
||||||
void XNMONITORSERVER_EXPORT XN_StopMonitorModelInfo();
|
void XNMONITORSERVER_EXPORT XN_StopMonitorModelInfo();
|
||||||
|
|
||||||
|
// 初始化引擎控制
|
||||||
|
int XNMONITORSERVER_EXPORT XN_InitializeEngineControl(char *errorMsg, int errorMsgSize);
|
||||||
|
|
||||||
|
// 暂停引擎
|
||||||
|
void XNMONITORSERVER_EXPORT XN_PauseEngine(char *errorMsg, int errorMsgSize);
|
||||||
|
|
||||||
|
// 恢复引擎
|
||||||
|
void XNMONITORSERVER_EXPORT XN_ResumeEngine(char *errorMsg, int errorMsgSize);
|
||||||
|
|
||||||
|
// 停止引擎
|
||||||
|
void XNMONITORSERVER_EXPORT XN_StopEngine(char *errorMsg, int errorMsgSize);
|
||||||
|
|
||||||
// // 主题管理接口
|
// // 主题管理接口
|
||||||
// XNDDSErrorCode XN_RegisterPublisher(const char *topicName, void **dataWriter);
|
// XNDDSErrorCode XN_RegisterPublisher(const char *topicName, void **dataWriter);
|
||||||
// XNDDSErrorCode XN_UnregisterPublisher(const char *topicName);
|
// XNDDSErrorCode XN_UnregisterPublisher(const char *topicName);
|
||||||
|
@ -10,6 +10,7 @@ class RunSim extends HTMLElement {
|
|||||||
this.currentSimulationId = null;
|
this.currentSimulationId = null;
|
||||||
this.reconnectAttempts = 0;
|
this.reconnectAttempts = 0;
|
||||||
this.maxReconnectAttempts = 3;
|
this.maxReconnectAttempts = 3;
|
||||||
|
this.isPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@ -286,10 +287,68 @@ class RunSim extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 连接到SSE事件源获取实时输出
|
// 连接到SSE事件源获取实时输出
|
||||||
|
async checkAndConnectToExistingSimulation() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/check-xnengine');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.running) {
|
||||||
|
this.showMessage('检测到正在运行的仿真,正在重新连接...');
|
||||||
|
|
||||||
|
// 更新UI以反映运行状态
|
||||||
|
const runButton = this.shadowRoot.querySelector('#run-simulation-button');
|
||||||
|
const pauseButton = this.shadowRoot.querySelector('#pause-simulation-button');
|
||||||
|
const stopButton = this.shadowRoot.querySelector('#stop-simulation-button');
|
||||||
|
|
||||||
|
if (runButton) {
|
||||||
|
runButton.disabled = true;
|
||||||
|
runButton.textContent = '运行中...';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseButton) {
|
||||||
|
pauseButton.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stopButton) {
|
||||||
|
stopButton.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用进程ID作为仿真ID
|
||||||
|
this.currentSimulationId = data.pid.toString();
|
||||||
|
|
||||||
|
// 清空并初始化输出框
|
||||||
|
const outputContent = this.shadowRoot.querySelector('#output-content');
|
||||||
|
outputContent.innerHTML = '重新连接到运行中的仿真...\n';
|
||||||
|
|
||||||
|
// 检查现有SSE连接是否有效
|
||||||
|
if (!this.eventSource || this.eventSource.readyState === 2) { // 2表示CLOSED
|
||||||
|
// 只有在没有有效连接时才创建新连接
|
||||||
|
this.connectToEventSource(this.currentSimulationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查引擎的暂停状态
|
||||||
|
pauseButton.textContent = this.isPaused ? '继续仿真' : '暂停仿真';
|
||||||
|
|
||||||
|
// 更新状态为已连接
|
||||||
|
this.showSuccess('已连接到运行中的仿真');
|
||||||
|
|
||||||
|
// 重置重连尝试次数
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
} else {
|
||||||
|
// 如果没有运行中的仿真,重置UI
|
||||||
|
this.resetSimulationButtons();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('检查XNEngine进程失败:', error);
|
||||||
|
this.showError('检查仿真状态失败: ' + error.message);
|
||||||
|
this.resetSimulationButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
connectToEventSource(simulationId) {
|
connectToEventSource(simulationId) {
|
||||||
// 关闭之前的连接
|
// 只有在没有有效连接时才创建新连接
|
||||||
if (this.eventSource) {
|
if (this.eventSource && this.eventSource.readyState !== 2) { // 2表示CLOSED
|
||||||
this.eventSource.close();
|
return; // 如果连接有效,直接返回
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建新的SSE连接
|
// 创建新的SSE连接
|
||||||
@ -452,6 +511,57 @@ class RunSim extends HTMLElement {
|
|||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
const outputContent = this.shadowRoot.querySelector('#output-content');
|
||||||
outputContent.innerHTML = '开始执行仿真...\n';
|
outputContent.innerHTML = '开始执行仿真...\n';
|
||||||
|
|
||||||
|
// 获取构型参数
|
||||||
|
const configResponse = await fetch(`/api/configurations/${confID}`);
|
||||||
|
if (!configResponse.ok) {
|
||||||
|
throw new Error('获取构型参数失败');
|
||||||
|
}
|
||||||
|
const configData = await configResponse.json();
|
||||||
|
|
||||||
|
// 从构型参数中提取域ID
|
||||||
|
const domainId = configData.DomainID;
|
||||||
|
if (!domainId) {
|
||||||
|
throw new Error('构型参数中未找到有效的域ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成唯一的监控器ID
|
||||||
|
const monitorId = `sim_${Date.now()}`;
|
||||||
|
|
||||||
|
// 初始化DDS监控
|
||||||
|
const ddsInitResponse = await fetch('/api/dds-monitor/initialize', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ domainId, monitorId })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ddsInitResponse.ok) {
|
||||||
|
throw new Error('初始化DDS监控失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ddsInitResult = await ddsInitResponse.json();
|
||||||
|
if (ddsInitResult.error) {
|
||||||
|
throw new Error(ddsInitResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化引擎控制
|
||||||
|
const initResponse = await fetch('/api/system-control/initialize', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!initResponse.ok) {
|
||||||
|
throw new Error('初始化引擎控制失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
const initResult = await initResponse.json();
|
||||||
|
if (!initResult.success) {
|
||||||
|
throw new Error(initResult.message || '初始化引擎控制失败');
|
||||||
|
}
|
||||||
|
|
||||||
// 准备启动参数
|
// 准备启动参数
|
||||||
const simulationArgs = ['-id', confID];
|
const simulationArgs = ['-id', confID];
|
||||||
|
|
||||||
@ -506,59 +616,6 @@ class RunSim extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加新方法:检查并连接到已有的仿真
|
|
||||||
async checkAndConnectToExistingSimulation() {
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/check-xnengine');
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (data.running) {
|
|
||||||
this.showMessage('检测到正在运行的仿真,正在重新连接...');
|
|
||||||
|
|
||||||
// 更新UI以反映运行状态
|
|
||||||
const runButton = this.shadowRoot.querySelector('#run-simulation-button');
|
|
||||||
const pauseButton = this.shadowRoot.querySelector('#pause-simulation-button');
|
|
||||||
const stopButton = this.shadowRoot.querySelector('#stop-simulation-button');
|
|
||||||
|
|
||||||
if (runButton) {
|
|
||||||
runButton.disabled = true;
|
|
||||||
runButton.textContent = '运行中...';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pauseButton) {
|
|
||||||
pauseButton.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopButton) {
|
|
||||||
stopButton.disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用进程ID作为仿真ID重新连接
|
|
||||||
this.currentSimulationId = data.pid.toString();
|
|
||||||
|
|
||||||
// 清空并初始化输出框
|
|
||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
|
||||||
outputContent.innerHTML = '重新连接到运行中的仿真...\n';
|
|
||||||
|
|
||||||
// 连接到SSE获取输出
|
|
||||||
this.connectToEventSource(this.currentSimulationId);
|
|
||||||
|
|
||||||
// 更新状态为已连接
|
|
||||||
this.showSuccess('已连接到运行中的仿真');
|
|
||||||
|
|
||||||
// 重置重连尝试次数
|
|
||||||
this.reconnectAttempts = 0;
|
|
||||||
} else {
|
|
||||||
// 如果没有运行中的仿真,重置UI
|
|
||||||
this.resetSimulationButtons();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('检查XNEngine进程失败:', error);
|
|
||||||
this.showError('检查仿真状态失败: ' + error.message);
|
|
||||||
this.resetSimulationButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加reactivate方法,用于从缓存中恢复时检查仿真状态
|
// 添加reactivate方法,用于从缓存中恢复时检查仿真状态
|
||||||
async reactivate() {
|
async reactivate() {
|
||||||
// 检查是否有XNEngine进程在运行
|
// 检查是否有XNEngine进程在运行
|
||||||
@ -971,27 +1028,41 @@ class RunSim extends HTMLElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const button = this.shadowRoot.querySelector('#pause-simulation-button');
|
const button = this.shadowRoot.querySelector('#pause-simulation-button');
|
||||||
const isPaused = button.textContent === '继续仿真';
|
|
||||||
|
|
||||||
// 调用后端API暂停/继续仿真
|
// 检查DDS状态
|
||||||
const response = await fetch('/api/pause-simulation', {
|
const ddsStatusResponse = await fetch('/api/dds-monitor/status');
|
||||||
|
if (!ddsStatusResponse.ok) {
|
||||||
|
throw new Error('获取DDS状态失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ddsStatus = await ddsStatusResponse.json();
|
||||||
|
if (!ddsStatus.isInitialized) {
|
||||||
|
throw new Error('DDS监控未初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据当前暂停状态调用不同的接口
|
||||||
|
const apiEndpoint = this.isPaused ? '/api/system-control/resume' : '/api/system-control/pause';
|
||||||
|
const response = await fetch(apiEndpoint, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
}
|
||||||
body: JSON.stringify({
|
|
||||||
id: simulationId,
|
|
||||||
pause: !isPaused
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('操作失败');
|
throw new Error('操作失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.message || '操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新暂停状态
|
||||||
|
this.isPaused = !this.isPaused;
|
||||||
// 更新按钮状态
|
// 更新按钮状态
|
||||||
button.textContent = isPaused ? '暂停仿真' : '继续仿真';
|
button.textContent = this.isPaused ? '继续仿真' : '暂停仿真';
|
||||||
this.showMessage(isPaused ? '仿真已继续' : '仿真已暂停');
|
this.showMessage(this.isPaused ? '仿真已暂停' : '仿真已继续');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('暂停/继续仿真失败:', error);
|
console.error('暂停/继续仿真失败:', error);
|
||||||
this.showError('操作失败: ' + error.message);
|
this.showError('操作失败: ' + error.message);
|
||||||
@ -1003,8 +1074,39 @@ class RunSim extends HTMLElement {
|
|||||||
if (!simulationId) return;
|
if (!simulationId) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用后端API停止仿真
|
// 检查DDS状态
|
||||||
const response = await fetch('/api/stop-simulation', {
|
const ddsStatusResponse = await fetch('/api/dds-monitor/status');
|
||||||
|
if (!ddsStatusResponse.ok) {
|
||||||
|
throw new Error('获取DDS状态失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ddsStatus = await ddsStatusResponse.json();
|
||||||
|
if (!ddsStatus.isInitialized) {
|
||||||
|
throw new Error('DDS监控未初始化');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 首先使用新的引擎控制接口
|
||||||
|
const response = await fetch('/api/system-control/stop', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('停止引擎失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.message || '停止引擎失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待5秒
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||||
|
|
||||||
|
// 调用老接口确保完全停止
|
||||||
|
const fallbackResponse = await fetch('/api/stop-simulation', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@ -1014,8 +1116,8 @@ class RunSim extends HTMLElement {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!fallbackResponse.ok) {
|
||||||
throw new Error('停止仿真失败');
|
console.warn('调用老接口停止仿真失败,但引擎已停止');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭SSE连接
|
// 关闭SSE连接
|
||||||
@ -1044,6 +1146,7 @@ class RunSim extends HTMLElement {
|
|||||||
pauseButton.disabled = true;
|
pauseButton.disabled = true;
|
||||||
stopButton.disabled = true;
|
stopButton.disabled = true;
|
||||||
pauseButton.textContent = '暂停仿真';
|
pauseButton.textContent = '暂停仿真';
|
||||||
|
this.isPaused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
XNSimHtml/routes/SystemControl.js
Normal file
99
XNSimHtml/routes/SystemControl.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const {
|
||||||
|
initializeEngineControl,
|
||||||
|
pauseEngine,
|
||||||
|
resumeEngine,
|
||||||
|
stopEngine
|
||||||
|
} = require('../utils/systemMonitor');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化引擎控制
|
||||||
|
* @route POST /api/system-control/initialize
|
||||||
|
* @returns {Object} 返回初始化结果
|
||||||
|
*/
|
||||||
|
router.post('/initialize', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = initializeEngineControl();
|
||||||
|
|
||||||
|
if (result.includes('失败')) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: result
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: result
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: `初始化引擎控制失败: ${error.message}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 暂停引擎
|
||||||
|
* @route POST /api/system-control/pause
|
||||||
|
* @returns {Object} 返回暂停操作结果
|
||||||
|
*/
|
||||||
|
router.post('/pause', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = pauseEngine();
|
||||||
|
res.json({
|
||||||
|
success: !result.includes('失败'),
|
||||||
|
message: result
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: `暂停引擎失败: ${error.message}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 恢复引擎
|
||||||
|
* @route POST /api/system-control/resume
|
||||||
|
* @returns {Object} 返回恢复操作结果
|
||||||
|
*/
|
||||||
|
router.post('/resume', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = resumeEngine();
|
||||||
|
res.json({
|
||||||
|
success: !result.includes('失败'),
|
||||||
|
message: result
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: `恢复引擎失败: ${error.message}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止引擎
|
||||||
|
* @route POST /api/system-control/stop
|
||||||
|
* @returns {Object} 返回停止操作结果
|
||||||
|
*/
|
||||||
|
router.post('/stop', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = stopEngine();
|
||||||
|
res.json({
|
||||||
|
success: !result.includes('失败'),
|
||||||
|
message: result
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: `停止引擎失败: ${error.message}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
@ -29,6 +29,7 @@ const systemLogRoutes = require('./routes/system-log');
|
|||||||
const ddsMonitorRoutes = require('./routes/DDSMonitor');
|
const ddsMonitorRoutes = require('./routes/DDSMonitor');
|
||||||
const systemMonitorRoutes = require('./routes/SystemMonitor');
|
const systemMonitorRoutes = require('./routes/SystemMonitor');
|
||||||
const modelMonitorRoutes = require('./routes/ModelMonitor');
|
const modelMonitorRoutes = require('./routes/ModelMonitor');
|
||||||
|
const systemControlRoutes = require('./routes/SystemControl');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
@ -99,6 +100,7 @@ app.use('/api/system-log', systemLogRoutes);
|
|||||||
app.use('/api/dds-monitor', ddsMonitorRoutes);
|
app.use('/api/dds-monitor', ddsMonitorRoutes);
|
||||||
app.use('/api/system-monitor', systemMonitorRoutes);
|
app.use('/api/system-monitor', systemMonitorRoutes);
|
||||||
app.use('/api/model-monitor', modelMonitorRoutes);
|
app.use('/api/model-monitor', modelMonitorRoutes);
|
||||||
|
app.use('/api/system-control', systemControlRoutes);
|
||||||
|
|
||||||
// 接口配置页面路由
|
// 接口配置页面路由
|
||||||
app.get('/interface-config', (req, res) => {
|
app.get('/interface-config', (req, res) => {
|
||||||
|
@ -49,7 +49,11 @@ try {
|
|||||||
'XN_StopMonitorSystemInfo': ['void', []],
|
'XN_StopMonitorSystemInfo': ['void', []],
|
||||||
'XN_StartMonitorModelInfo': ['int', [StringType, 'int']],
|
'XN_StartMonitorModelInfo': ['int', [StringType, 'int']],
|
||||||
'XN_GetModelInfo': ['int', [StringType, 'int']],
|
'XN_GetModelInfo': ['int', [StringType, 'int']],
|
||||||
'XN_StopMonitorModelInfo': ['void', []]
|
'XN_StopMonitorModelInfo': ['void', []],
|
||||||
|
'XN_InitializeEngineControl': ['int', [StringType, 'int']],
|
||||||
|
'XN_PauseEngine': ['void', [StringType, 'int']],
|
||||||
|
'XN_ResumeEngine': ['void', [StringType, 'int']],
|
||||||
|
'XN_StopEngine': ['void', [StringType, 'int']]
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`加载 ${monitorLibName} 失败:`, error);
|
console.error(`加载 ${monitorLibName} 失败:`, error);
|
||||||
@ -225,6 +229,68 @@ function stopMonitorModelInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化引擎控制
|
||||||
|
function initializeEngineControl() {
|
||||||
|
if (!monitorLib) {
|
||||||
|
return '监控服务器库未加载';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const errorMsg = Buffer.alloc(1024);
|
||||||
|
const result = monitorLib.XN_InitializeEngineControl(errorMsg, errorMsg.length);
|
||||||
|
if (result !== 0) {
|
||||||
|
return `初始化引擎控制失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
|
||||||
|
}
|
||||||
|
return '初始化引擎控制成功';
|
||||||
|
} catch (error) {
|
||||||
|
return `初始化引擎控制失败: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂停引擎
|
||||||
|
function pauseEngine() {
|
||||||
|
if (!monitorLib) {
|
||||||
|
return '监控服务器库未加载';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const errorMsg = Buffer.alloc(1024);
|
||||||
|
monitorLib.XN_PauseEngine(errorMsg, errorMsg.length);
|
||||||
|
const error = errorMsg.toString('utf8').replace(/\0/g, '');
|
||||||
|
return error ? `暂停引擎失败: ${error}` : '暂停引擎成功';
|
||||||
|
} catch (error) {
|
||||||
|
return `暂停引擎失败: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复引擎
|
||||||
|
function resumeEngine() {
|
||||||
|
if (!monitorLib) {
|
||||||
|
return '监控服务器库未加载';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const errorMsg = Buffer.alloc(1024);
|
||||||
|
monitorLib.XN_ResumeEngine(errorMsg, errorMsg.length);
|
||||||
|
const error = errorMsg.toString('utf8').replace(/\0/g, '');
|
||||||
|
return error ? `恢复引擎失败: ${error}` : '恢复引擎成功';
|
||||||
|
} catch (error) {
|
||||||
|
return `恢复引擎失败: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止引擎
|
||||||
|
function stopEngine() {
|
||||||
|
if (!monitorLib) {
|
||||||
|
return '监控服务器库未加载';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const errorMsg = Buffer.alloc(1024);
|
||||||
|
monitorLib.XN_StopEngine(errorMsg, errorMsg.length);
|
||||||
|
const error = errorMsg.toString('utf8').replace(/\0/g, '');
|
||||||
|
return error ? `停止引擎失败: ${error}` : '停止引擎成功';
|
||||||
|
} catch (error) {
|
||||||
|
return `停止引擎失败: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loginLib,
|
loginLib,
|
||||||
monitorLib,
|
monitorLib,
|
||||||
@ -238,5 +304,9 @@ module.exports = {
|
|||||||
stopMonitorSystemInfo,
|
stopMonitorSystemInfo,
|
||||||
startMonitorModelInfo,
|
startMonitorModelInfo,
|
||||||
getModelInfo,
|
getModelInfo,
|
||||||
stopMonitorModelInfo
|
stopMonitorModelInfo,
|
||||||
|
initializeEngineControl,
|
||||||
|
pauseEngine,
|
||||||
|
resumeEngine,
|
||||||
|
stopEngine
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user