XNSim/XNEngine/XNEngine.cpp
2025-04-28 12:25:20 +08:00

404 lines
14 KiB
C++
Executable File

/**
* @file XNEngine.cpp
* @author jinchao
* @brief 引擎类
* @version 1.0
* @date 2025-02-14
*
* @copyright Copyright (c) 2025 COMAC
*
*/
#include "XNEngine.h"
#include <QTimer>
#include <QCoreApplication>
#include "../XNCore/XNTimeManager.h"
#include "../XNCore/XNThreadManager.h"
#include "../XNCore/XNDDSManager.h"
#include "../XNCore/XNEventManager.h"
#include "../XNCore/XNServiceManager.h"
#include "../XNCore/XNModelManager.h"
#include "../XNCore/XNScenarioManager.h"
// 引擎类构造函数
XNEngine::XNEngine(QObject *parent) : QObject(parent)
{
// 设置对象名称
setObjectName("XNEngine");
// 创建框架对象
framework = new XNFramework();
// 连接初始化信号和槽
connect(this, &XNEngine::InitializeSignal, framework, &XNFramework::Initialize);
// 连接准备执行信号和槽
connect(this, &XNEngine::PrepareforExecuteSignal, framework, &XNFramework::OnPrepareForExecute);
// 连接初始化成功信号和槽
connect(framework, &XNFramework::InitializeSuccess, this, &XNEngine::OnInitializeSuccess);
// 连接准备执行成功信号和槽
connect(framework, &XNFramework::PrepareForExecuteSuccess, this,
&XNEngine::OnPrepareforExecuteSuccess);
// 连接仿真控制信号和槽
connect(this, &XNEngine::SimControlSignal, framework, &XNFramework::OnSimControl);
// 引擎状态写入器
engineStatusWriter = nullptr;
// 测试模式
isTestMode = false;
}
// 引擎类析构函数
XNEngine::~XNEngine()
{
}
// 仿真控制监听器
void XNEngine::SimControlListener(const XNSim::XNSimControl::XNRuntimeControl &cmd)
{
if (cmd.XNSimCmd() == 1) {
// 如果命令是暂停
emit SimControlSignal(0, SimControlCmd::Suspend);
} else if (cmd.XNSimCmd() == 2) {
// 如果命令是继续
emit SimControlSignal(0, SimControlCmd::Continue);
} else if (cmd.XNSimCmd() == 3) {
// 如果命令是终止
emit SimControlSignal(0, SimControlCmd::Abort);
//TODO 后续收到结束指令后再结束,还需要最后发一次终止状态
emit StopTimer();
// 退出应用程序
QCoreApplication::quit();
}
}
// 设置日志级别
bool XNEngine::SetLogLevel(const QString &XmlPath)
{
// 打开配置文件
QFile file(XmlPath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qFatal("0x1003 Failed to open the runtime environment configuration file, "
"the engine will exit!");
}
// 解析配置文件
QDomDocument doc;
if (!doc.setContent(&file)) {
qFatal("0x1004 Failed to parse the runtime environment configuration file, "
"the engine will exit!");
}
// 获取根元素
QDomElement root = doc.documentElement();
// 顺便读取一下CPU亲和性
int cpus = sysconf(_SC_NPROCESSORS_ONLN);
qInfo("Current number of CPU cores-> %d", cpus);
// 设置CPU亲和性
cpu_set_t mask;
CPU_ZERO(&mask);
CPUAffinity = 0;
QDomNode EnvironmentNode = root.firstChildElement("Environment");
QString tmp = EnvironmentNode.toElement().attribute("CPUAffinity");
QStringList cpuAffinityList = tmp.split(",", Qt::SkipEmptyParts);
for (const QString &cpuAffinity : cpuAffinityList) {
bool ok;
quint32 cpuIndex = cpuAffinity.toUInt(&ok);
if (ok && cpuIndex < cpus) {
CPUAffinity |= (1 << cpuIndex);
CPU_SET(cpuIndex, &mask);
}
}
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
qFatal("0x1020 Failed to set engine CPU affinity-> %s", strerror(errno));
}
qInfo("Successfully set engine CPU affinity-> %u", CPUAffinity);
// 锁定内存
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
qFatal("0x1021 Failed to lock engine memory-> %s", strerror(errno));
}
qInfo("Successfully locked engine memory!");
// 获取配置文件中的控制台输出元素
QDomNode consoleOutputNode = root.firstChildElement("ConsoleOutput");
if (consoleOutputNode.isNull()) {
qWarning("The runtime environment configuration file does not contain"
"the ConsoleOutput element, the Console will Output all Log!");
} else {
// 获取配置文件中的调试日志输出元素
QString debugConsoleOutput = consoleOutputNode.toElement().attribute("Debug");
if (debugConsoleOutput == "true" || debugConsoleOutput == "1"
|| debugConsoleOutput == "True" || debugConsoleOutput == "TRUE") {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, true);
} else {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Debug, false);
}
// 获取配置文件中的信息日志输出元素
QString infoConsoleOutput = consoleOutputNode.toElement().attribute("Info");
if (infoConsoleOutput == "true" || infoConsoleOutput == "1" || infoConsoleOutput == "True"
|| infoConsoleOutput == "TRUE") {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, true);
} else {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Info, false);
}
// 获取配置文件中的警告日志输出元素
QString warningConsoleOutput = consoleOutputNode.toElement().attribute("Warning");
if (warningConsoleOutput == "true" || warningConsoleOutput == "1"
|| warningConsoleOutput == "True" || warningConsoleOutput == "TRUE") {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, true);
} else {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Warning, false);
}
// 获取配置文件中的错误日志输出元素
QString errorConsoleOutput = consoleOutputNode.toElement().attribute("Error");
if (errorConsoleOutput == "true" || errorConsoleOutput == "1"
|| errorConsoleOutput == "True" || errorConsoleOutput == "TRUE") {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, true);
} else {
XNLogger::instance().enableConsoleOutput(XNLogger::LogLevel::Error, false);
}
}
// 获取配置文件中的日志元素
QDomNode logNode = root.firstChildElement("Log");
if (logNode.isNull()) {
qWarning("The runtime environment configuration file does not contain"
"the Log element, the Log File will record all Log!");
} else {
// 获取配置文件中的调试日志输出元素
QString debugLog = logNode.toElement().attribute("Debug");
if (debugLog == "true" || debugLog == "1" || debugLog == "True" || debugLog == "TRUE") {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, true);
} else {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Debug, false);
}
// 获取配置文件中的信息日志输出元素
QString infoLog = logNode.toElement().attribute("Info");
if (infoLog == "true" || infoLog == "1" || infoLog == "True" || infoLog == "TRUE") {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, true);
} else {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Info, false);
}
// 获取配置文件中的警告日志输出元素
QString warningLog = logNode.toElement().attribute("Warning");
if (warningLog == "true" || warningLog == "1" || warningLog == "True"
|| warningLog == "TRUE") {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, true);
} else {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Warning, false);
}
// 获取配置文件中的错误日志输出元素
QString errorLog = logNode.toElement().attribute("Error");
if (errorLog == "true" || errorLog == "1" || errorLog == "True" || errorLog == "TRUE") {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, true);
} else {
XNLogger::instance().enableFileOutput(XNLogger::LogLevel::Error, false);
}
}
// 关闭配置文件
file.close();
// 返回成功
return true;
}
// 发布引擎状态
void XNEngine::PublishEngineStatus()
{
// 如果引擎状态写入器存在
if (engineStatusWriter) {
// 创建引擎状态对象
XNSim::XNSimStatus::XNEngineStatus engineStatus;
// 创建内核状态对象
XNSim::XNSimStatus::XNCoreStatus coreStatus;
// 设置引擎名称
engineStatus.XNEngineName(objectName().toStdString());
// 设置引擎ID
engineStatus.XNEngineID(getpid());
// 设置引擎亲和性
engineStatus.XNEngineAff(CPUAffinity);
// 获取时间管理器
XNTimeManager *timeManager = framework->findChild<XNTimeManager *>();
// 如果时间管理器存在
if (timeManager) {
// 设置引擎状态
engineStatus.XNEngineSt((quint32)timeManager->GetStatus());
// 设置内核状态
coreStatus.XNTMStatus((quint32)timeManager->GetFrameObjectStatus());
} else {
// 设置引擎状态
engineStatus.XNEngineSt(4);
// 设置内核状态
coreStatus.XNTMStatus(2);
}
// 获取线程管理器
XNThreadManager *threadManager = framework->findChild<XNThreadManager *>();
// 如果线程管理器存在
if (threadManager) {
// 设置内核状态
coreStatus.XNThMStatus((quint32)threadManager->GetFrameObjectStatus());
// 设置引擎状态
engineStatus.XNThCnt(threadManager->GetThreadCount());
} else {
// 设置内核状态
coreStatus.XNThMStatus(2);
}
// 获取DDS管理器
XNDDSManager *ddsManager = framework->findChild<XNDDSManager *>();
// 如果DDS管理器存在
if (ddsManager) {
// 设置内核状态
coreStatus.XNDMStatus((quint32)ddsManager->GetFrameObjectStatus());
} else {
// 设置内核状态
coreStatus.XNDMStatus(2);
}
// 获取事件管理器
XNEventManager *eventManager = framework->findChild<XNEventManager *>();
// 如果事件管理器存在
if (eventManager) {
// 设置内核状态
coreStatus.XNEMStatus((quint32)eventManager->GetFrameObjectStatus());
} else {
// 设置内核状态
coreStatus.XNEMStatus(2);
}
// 获取服务管理器
XNServiceManager *serviceManager = framework->findChild<XNServiceManager *>();
// 如果服务管理器存在
if (serviceManager) {
// 设置内核状态
coreStatus.XNSMStatus((quint32)serviceManager->GetFrameObjectStatus());
} else {
// 设置内核状态
coreStatus.XNSMStatus(2);
}
// 获取模型管理器
XNModelManager *modelManager = framework->findChild<XNModelManager *>();
// 如果模型管理器存在
if (modelManager) {
// 设置内核状态
coreStatus.XNMMStatus((quint32)modelManager->GetFrameObjectStatus());
} else {
// 设置内核状态
coreStatus.XNMMStatus(2);
}
// 获取场景管理器
XNScenarioManager *scenarioManager = framework->findChild<XNScenarioManager *>();
// 如果场景管理器存在
if (scenarioManager) {
// 设置内核状态
coreStatus.XNSDStatus((quint32)scenarioManager->GetFrameObjectStatus());
} else {
// 设置内核状态
coreStatus.XNSDStatus(2);
}
// 设置框架状态
coreStatus.XNFWStatus((quint32)frameworkStatus);
// 设置引擎状态
engineStatus.XNCoreSt(coreStatus);
// 写入引擎状态
engineStatusWriter->write(&engineStatus);
// 记录调试日志
LOG_DEBUG("XNEngine Write DDS!");
}
}
// 运行引擎
bool XNEngine::Run(const QString &XmlPath)
{
// 设置日志级别
bool isReady = SetLogLevel(XmlPath);
// 如果设置日志级别失败
if (!isReady) {
// 返回失败
return false;
}
// 设置场景XML路径
framework->SetScenarioXml(XmlPath);
// 设置CPU亲和性
framework->SetCpuAffinity(CPUAffinity);
// 单次触发初始化信号
QTimer::singleShot(50, [this]() { emit InitializeSignal(); });
// 返回成功
return true;
}
// 初始化成功
void XNEngine::OnInitializeSuccess(bool isSuccess)
{
if (isSuccess) { // 如果初始化成功
// 如果不是测试模式
if (!isTestMode) {
// 设置框架状态
frameworkStatus = XNFrameObjectStatus::Initialized;
// 记录信息日志
LOG_INFO("XNEngine Initialize Success!");
// 触发准备执行信号
emit PrepareforExecuteSignal();
} else {
// 记录信息日志
LOG_INFO("Verification passed!");
// 退出应用程序
QCoreApplication::quit();
}
} else { // 如果初始化失败
// 如果不是测试模式
if (!isTestMode) {
// 设置框架状态
frameworkStatus = XNFrameObjectStatus::Unknown;
// 记录错误日志
qFatal("0x1006 Failed to initialize the engine, the engine will exit!");
} else {
// 记录信息日志
LOG_INFO("Verification failed!");
// 退出应用程序
QCoreApplication::quit();
}
}
}
// 准备执行成功
void XNEngine::OnPrepareforExecuteSuccess(bool isSuccess)
{
// 如果准备执行成功
if (isSuccess) {
// 设置框架状态
frameworkStatus = XNFrameObjectStatus::Ready;
// 获取DDS管理器
XNDDSManager *ddsManager = framework->findChild<XNDDSManager *>();
// 如果DDS管理器存在
if (ddsManager) {
// 注册引擎状态发布者
engineStatusWriter =
ddsManager->RegisterPublisher<XNSim::XNSimStatus::XNEngineStatusPubSubType>(
"XNSim::XNSimStatus::XNEngineStatus", 0);
// 如果引擎状态写入器存在
if (engineStatusWriter) {
// 创建定时器
QTimer *timer = new QTimer(this);
// 设置定时器对象名称
timer->setObjectName("XNEngineStatusTimer");
// 连接定时器超时信号和槽
connect(timer, &QTimer::timeout, this, &XNEngine::PublishEngineStatus);
// 连接停止定时器信号和槽
connect(this, &XNEngine::StopTimer, timer, &QTimer::stop, Qt::QueuedConnection);
// 启动定时器
timer->start(1000); // Timer will trigger every second
}
// 注册仿真控制订阅者
auto func = std::bind(&XNEngine::SimControlListener, this, std::placeholders::_1);
ddsManager->RegisterSubscriber<XNSim::XNSimControl::XNRuntimeControlPubSubType>(
"XNSim::XNSimControl::XNRuntimeControl", 0, func);
// 触发仿真控制信号
emit SimControlSignal(0, SimControlCmd::Start);
} else {
// 记录错误日志
qFatal("0x1007 Failed to prepare for execution, the engine will exit!");
}
} else {
// 设置框架状态
frameworkStatus = XNFrameObjectStatus::Unknown;
// 记录错误日志
qFatal("0x1007 Failed to prepare for execution, the engine will exit!");
}
}
// 设置测试模式
void XNEngine::SetTestMode(bool isTestMode)
{
// 设置测试模式
this->isTestMode = isTestMode;
}