Compare commits

..

2 Commits

Author SHA1 Message Date
49f139f508 ignore log 2025-04-28 16:43:26 +08:00
3ec47bdc72 增加UDP测试 2025-04-28 16:41:21 +08:00
29 changed files with 2082 additions and 224 deletions

1
.gitignore vendored
View File

@ -34,3 +34,4 @@
# CMakeBuild
build/
log/

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scenario>
<Environment
OSName="Debian"
Version="11"
RTXVersion="preempt-rt"
CPUAffinity="0,1"
BaseFrequency="120"
WorkPath="/home/jin/Myprj/XNSim/Release/"
ModelsPath="Models/"
ServicesPath="Services/"
DomainID="10"
/>
<ConsoleOutput Debug="1" Info="1" Error="1" Warning="1" />
<Log Debug="0" Info="1" Error="1" Warning="1" />
<ModelGroup Name="新模型组" FreqGroup="0" Priority="99" CPUAff="0">
<!-- 这里添加模型 -->
</ModelGroup>
<ServicesList>
<!-- 这里添加服务 -->
</ServicesList>
</Scenario>

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scenario>
<Environment
OSName="Debian"
Version="11"
RTXVersion="preempt-rt"
CPUAffinity="0,1"
BaseFrequency="120"
WorkPath="/home/jin/Myprj/XNSim/Release/"
ModelsPath="Models/"
ServicesPath="Services/"
DomainID="10"
/>
<ConsoleOutput Debug="1" Info="1" Error="1" Warning="1" />
<Log Debug="0" Info="1" Error="1" Warning="1" />
<ModelGroup Name="新模型组" FreqGroup="0" Priority="99" CPUAff="0">
<!-- 这里添加模型 -->
</ModelGroup>
<ServicesList>
<!-- 这里添加服务 -->
</ServicesList>
</Scenario>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scenario>
<Environment OSName="Debian" Version="11" RTXVersion="preempt-rt" CPUAffinity="0,1" BaseFrequency="120" WorkPath="/home/jin/Myprj/XNSim/Release/" ModelsPath="Models/" ServicesPath="Services/" DomainID="10"/>
<ConsoleOutput Debug="1" Info="1" Error="1" Warning="1"/>
<Log Debug="0" Info="1" Error="1" Warning="1"/>
<ModelGroup Name="新模型组" FreqGroup="0" Priority="99" CPUAff="0">
<!-- 这里添加模型 -->
</ModelGroup>
<ServicesList>
<!-- 这里添加服务 -->
</ServicesList>
</Scenario>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scenario>
<Environment OSName="RT-Linux" Version="5.10.0-26-rt-amd64" RTXVersion="none" BaseFrequency="100" WorkPath="." ModelsPath="./models" ServicesPath="./services" CPUAffinity="0,1" DomainID="0"/>
<ConsoleOutput Debug="1" Info="1" Warning="1" Error="1"/>
<Log Debug="0" Info="1" Warning="1" Error="1"/>
<ModelGroupList>
<ModelGroup Name="DefaultGroup" FreqGroup="0" Priority="99" CPUAff="0">
<Model Name="DefaultModel" ClassName="XNModel"/>
</ModelGroup>
</ModelGroupList>
<ServicesList>
<Service Name="DefaultService" ClassName="XNService"/>
</ServicesList>
</Scenario>

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scenario>
<Environment OSName="Debian" Version="11" RTXVersion="preempt-rt" CPUAffinity="0,1" BaseFrequency="120" WorkPath="/home/jin/Myprj/XNSim/Release/" ModelsPath="Models/" ServicesPath="Services/" DomainID="10"/>
<Environment OSName="Debian" Version="11" RTXVersion="preempt-rt" CPUAffinity="0,1" BaseFrequency="120" WorkPath="/home/jin/MyCode/XNSim/Release/" ModelsPath="Models/" ServicesPath="Services/" DomainID="10"/>
<ConsoleOutput Debug="1" Info="1" Error="1" Warning="1"/>
<Log Debug="0" Info="1" Error="1" Warning="1"/>
<ModelGroup Name="本体模型组" FreqGroup="0" Priority="99" CPUAff="0">
<Model Name="ATA04气动模型" ClassName="XNAerodynamics"/>
<Model Name="ATA04地面操纵模型" ClassName="XNGroundHandling"/>
<Model Name="ATA04质量模型" ClassName="XNWeightBalance"/>
<Model Name="ATA04数据处理模型" ClassName="XNATA04DataProcessor"/>
<!--Model Name="ATA04数据处理模型" ClassName="XNATA04DataProcessor"/-->
</ModelGroup>
<ServicesList>
<Service Name="UDP通信服务" ClassName="XNUDPService"/>

View File

@ -5,8 +5,8 @@
Version="11"
RTXVersion="preempt-rt"
CPUAffinity="0,1"
BaseFrequency="120"
WorkPath="/home/jin/Myprj/XNSim/Release/"
BaseFrequency="60"
WorkPath="/home/jin/MyCode/XNSim/Release/"
ModelsPath="Models/"
ServicesPath="Services/"
DomainID="10"

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scenario>
<Environment OSName="Debian" Version="11" RTXVersion="preempt-rt" CPUAffinity="0,1" BaseFrequency="120" WorkPath="/home/jin/MyCode/XNSim/Release/" ModelsPath="Models/" ServicesPath="Services/" DomainID="10"/>
<ConsoleOutput Debug="1" Info="1" Error="1" Warning="1"/>
<Log Debug="0" Info="1" Error="1" Warning="1"/>
<ModelGroup Name="本体模型组" FreqGroup="0" Priority="99" CPUAff="0">
<Model Name="ATA04气动模型" ClassName="XNAerodynamics"/>
<Model Name="ATA04地面操纵模型" ClassName="XNGroundHandling"/>
<Model Name="ATA04质量模型" ClassName="XNWeightBalance"/>
<Model Name="ATA04数据处理模型" ClassName="XNATA04DataProcessor"/>
</ModelGroup>
<ServicesList>
<Service Name="UDP通信服务" ClassName="XNUDPService"/>
<Service Name="UDP通信测试服务" ClassName="XNUDPTestService"/>
</ServicesList>
</Scenario>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Service>
<Name>123</Name>
<Description>服务描述</Description>
<Author>sdgsdf</Author>
<Version>1.0.0</Version>
<CreateTime>2025-04-21 16:16:14</CreateTime>
<ChangeTime>2025-04-21 16:16:46</ChangeTime>
<CommandList>
<Command Name="asdf" Call="asdf" Description="asdf" />
</CommandList>
</Service>

28
Release/Services/XNUDPService.scfg Executable file → Normal file
View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Service>
<Name>XNUDPService</Name>
<Description>UDP通信服务</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-04 10:00:00</CreateTime>
<ChangeTime>2025-02-04 10:00:00</ChangeTime>
<CommandList>
<Command Name="TestCmd" Description="Test" Call="TestCall" />
</CommandList>
<UDP>
<LocalPort>12345</LocalPort>
<TargetHost>127.0.0.1</TargetHost>
<TargetPort>54321</TargetPort>
</UDP>
<Name>XNUDPService</Name>
<Description>UDP通信服务</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-04 10:00:00</CreateTime>
<ChangeTime>2025-02-04 10:00:00</ChangeTime>
<CommandList>
<Command Name="TestCmd" Description="Test" Call="TestCall"/>
</CommandList>
<UDP>
<LocalPort>12345</LocalPort>
<TargetHost>127.0.0.1</TargetHost>
<TargetPort>54321</TargetPort>
</UDP>
</Service>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Service>
<Name>XNUDPService</Name>
<Description>UDP通信服务</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-04 10:00:00</CreateTime>
<ChangeTime>2025-02-04 10:00:00</ChangeTime>
<CommandList></CommandList>
<UDP>
<LocalPort>12345</LocalPort>
<TargetHost>127.0.0.1</TargetHost>
<TargetPort>54321</TargetPort>
</UDP>
</Service>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Service>
<Name>XNUDPTestService</Name>
<Description>UDP通信服务</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-04 10:00:00</CreateTime>
<ChangeTime>2025-02-04 10:00:00</ChangeTime>
<CommandList>
<Command Name="TestCmd" Description="Test" Call="TestCall"/>
</CommandList>
<UDP>
<LocalPort>54321</LocalPort>
<TargetHost>127.0.0.1</TargetHost>
<TargetPort>12345</TargetPort>
</UDP>
</Service>

View File

@ -1,3 +1,3 @@
/home/jin/Myprj/XNSim/Release/lib
/home/jin/Myprj/XNSim/Release/Models
/home/jin/Myprj/XNSim/Release/Services
/home/jin/MyCode/XNSim/Release/lib
/home/jin/MyCode/XNSim/Release/Models
/home/jin/MyCode/XNSim/Release/Services

View File

@ -1,4 +1,4 @@
export XNCore=/home/jin/Myprj/XNSim/Release
export XNCore=/home/jin/MyCode/XNSim/Release
export PATH=$XNCore:$PATH
export LD_LIBRARY_PATH=$XNCore/lib:$LD_LIBRARY_PATH
export QT_QPA_PLATFORM=xcb

View File

@ -54,6 +54,7 @@ void XNATA04DataProcessor::StepUpdate()
Q_D(XNATA04DataProcessor);
XNModelObject::StepUpdate();
SendUdpData();
SendUdpTestData();
}
void XNATA04DataProcessor::SendUdpData()
@ -981,97 +982,124 @@ void XNATA04DataProcessor::OnAeroInput(const QVariant &data)
{
Q_D(XNATA04DataProcessor);
QByteArray inputData = data.toByteArray();
if (inputData.size() <= 5 || inputData[0] != 0x0b || inputData[1] != 0x04
|| inputData[2] != 0x00 || inputData[3] != 0x00 || inputData[4] != inputData.size()) {
LOG_WARNING("ATA04DataProcessor::OnAeroInput: invalid input data");
// 基本验证:长度和包头前四个字节
if (inputData.size() <= 5) {
LOG_WARNING("ATA04DataProcessor::OnAeroInput: data too short, size=%d", inputData.size());
return;
}
// 现在我们知道数据包确实以0b 04 00 00开头
if (inputData[0] != 0x0b || inputData[1] != 0x04 || inputData[2] != 0x00
|| inputData[3] != 0x00) {
LOG_WARNING("ATA04DataProcessor::OnAeroInput: invalid header, expected 0b 04 00 00, got "
"%02x %02x %02x %02x",
(quint8)inputData[0], (quint8)inputData[1], (quint8)inputData[2],
(quint8)inputData[3]);
return;
}
// 使用与发送方相同版本的QDataStream读取数据
QDataStream inputStream(&inputData, QIODevice::ReadOnly);
inputStream.setByteOrder(QDataStream::LittleEndian);
inputStream.setVersion(QDataStream::Qt_6_0);
// 跳过5字节的头
for (int i = 0; i < 5; i++) {
char tmp;
inputStream >> tmp;
}
QMutexLocker locker(&d->_aeroInputMutex);
double tmp;
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_alpha_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_alpdot_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_beta_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_press_alt_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_tas_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_mach_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_nx_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_ny_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_nz_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_p_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_q_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_r_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_qbar_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_blcg_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_bscg_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_wlcg_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_stab_f8(tmp);
std::array<double, 10> tmpArray;
for (int i = 0; i < 10; i++) {
inputStream >> tmpArray[i];
// 尝试读取数据,并添加异常处理
try {
double tmp;
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_alpha_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_alpdot_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_beta_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_press_alt_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_tas_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_mach_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_nx_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_ny_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_nz_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_p_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_q_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_r_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_qbar_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_blcg_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_bscg_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_wlcg_f8(tmp);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_stab_f8(tmp);
std::array<double, 10> tmpArray;
for (int i = 0; i < 10; i++) {
inputStream >> tmpArray[i];
}
d->_aeroInput.l_04_i_aerocomac_ail_f8(tmpArray);
std::array<double, 4> tmpArray2;
for (int i = 0; i < 4; i++) {
inputStream >> tmpArray2[i];
}
d->_aeroInput.l_04_i_aerocomac_elv_f8(tmpArray2);
std::array<double, 2> tmpArray3;
for (int i = 0; i < 2; i++) {
inputStream >> tmpArray3[i];
}
d->_aeroInput.l_04_i_aerocomac_rud_f8(tmpArray3);
std::array<double, 7> tmpArray4;
for (int i = 0; i < 7; i++) {
inputStream >> tmpArray4[i];
}
d->_aeroInput.l_04_i_aerocomac_gear_f8(tmpArray4);
for (int i = 0; i < 10; i++) {
inputStream >> tmpArray[i];
}
d->_aeroInput.l_04_i_aerocomac_flap_f8(tmpArray);
std::array<double, 20> tmpArray5;
for (int i = 0; i < 20; i++) {
inputStream >> tmpArray5[i];
}
d->_aeroInput.l_04_i_aerocomac_slat_f8(tmpArray5);
for (int i = 0; i < 20; i++) {
inputStream >> tmpArray5[i];
}
d->_aeroInput.l_04_i_aerocomac_spl_f8(tmpArray5);
for (int i = 0; i < 4; i++) {
inputStream >> tmpArray2[i];
}
d->_aeroInput.l_04_i_aerocomac_tnet_f8(tmpArray2);
for (int i = 0; i < 20; i++) {
inputStream >> tmpArray5[i];
}
d->_aeroInput.l_04_i_aerocomac_kice_f8(tmpArray5);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_alt_agl_f8(tmp);
d->_dataWriters["XNSim::ATA04::Aerodynamics_input"]->write(&d->_aeroInput);
} catch (const std::exception &e) {
LOG_WARNING("ATA04DataProcessor::OnAeroInput: exception during data parsing: %s", e.what());
return;
} catch (...) {
LOG_WARNING("ATA04DataProcessor::OnAeroInput: unknown exception during data parsing");
return;
}
d->_aeroInput.l_04_i_aerocomac_ail_f8(tmpArray);
std::array<double, 4> tmpArray2;
for (int i = 0; i < 4; i++) {
inputStream >> tmpArray2[i];
}
d->_aeroInput.l_04_i_aerocomac_elv_f8(tmpArray2);
std::array<double, 2> tmpArray3;
for (int i = 0; i < 2; i++) {
inputStream >> tmpArray3[i];
}
d->_aeroInput.l_04_i_aerocomac_rud_f8(tmpArray3);
std::array<double, 7> tmpArray4;
for (int i = 0; i < 7; i++) {
inputStream >> tmpArray4[i];
}
d->_aeroInput.l_04_i_aerocomac_gear_f8(tmpArray4);
for (int i = 0; i < 10; i++) {
inputStream >> tmpArray[i];
}
d->_aeroInput.l_04_i_aerocomac_flap_f8(tmpArray);
std::array<double, 20> tmpArray5;
for (int i = 0; i < 20; i++) {
inputStream >> tmpArray5[i];
}
d->_aeroInput.l_04_i_aerocomac_slat_f8(tmpArray5);
for (int i = 0; i < 20; i++) {
inputStream >> tmpArray5[i];
}
d->_aeroInput.l_04_i_aerocomac_spl_f8(tmpArray5);
for (int i = 0; i < 4; i++) {
inputStream >> tmpArray2[i];
}
d->_aeroInput.l_04_i_aerocomac_tnet_f8(tmpArray2);
for (int i = 0; i < 20; i++) {
inputStream >> tmpArray5[i];
}
d->_aeroInput.l_04_i_aerocomac_kice_f8(tmpArray5);
inputStream >> tmp;
d->_aeroInput.l_04_i_aerocomac_alt_agl_f8(tmp);
d->_dataWriters["XNSim::ATA04::Aerodynamics_input"]->write(&d->_aeroInput);
}
void XNATA04DataProcessor::OnWbOutput(const XNSim::ATA04::WeightBalance_output &input)
@ -1115,3 +1143,280 @@ void XNATA04DataProcessor::OnGhHeartbeat(const XNSim::ATA04::GroundHandling_hear
QMutexLocker locker(&d->_ghHeartbeatMutex);
d->_ghHeartbeat = input;
}
void XNATA04DataProcessor::SendUdpTestData()
{
Q_D(XNATA04DataProcessor);
// 创建气动输入(AeroInput)数据包
QByteArray aeroData;
QDataStream aeroStream(&aeroData, QIODevice::WriteOnly);
aeroStream.setByteOrder(QDataStream::LittleEndian);
aeroStream.setVersion(QDataStream::Qt_6_0);
// 气动输入数据包头 (0x0b=从外部输入, 0x04=ATA04, 0x00=气动模型, 0x00=输入数据)
quint8 aeroHeader[5] = {0x0b, 0x04, 0x00, 0x00, 0x00};
aeroStream << aeroHeader[0] << aeroHeader[1] << aeroHeader[2] << aeroHeader[3] << aeroHeader[4];
// 气动数据字段
aeroStream << (double)5.0; // alpha
aeroStream << (double)0.5; // alpdot
aeroStream << (double)1.0; // beta
aeroStream << (double)10000.0; // press_alt
aeroStream << (double)250.0; // tas
aeroStream << (double)0.8; // mach
aeroStream << (double)0.2; // nx
aeroStream << (double)0.0; // ny
aeroStream << (double)1.0; // nz
aeroStream << (double)0.0; // p
aeroStream << (double)0.0; // q
aeroStream << (double)0.0; // r
aeroStream << (double)12000.0; // qbar
aeroStream << (double)0.0; // blcg
aeroStream << (double)0.0; // bscg
aeroStream << (double)0.0; // wlcg
aeroStream << (double)0.0; // stab
// ail_f8 数组需要10个double
for (int i = 0; i < 10; i++) {
aeroStream << (double)0.0;
}
// elv_f8 数组需要4个double
for (int i = 0; i < 4; i++) {
aeroStream << (double)0.0;
}
// rud_f8 数组需要2个double
for (int i = 0; i < 2; i++) {
aeroStream << (double)0.0;
}
// gear_f8 数组需要7个double
for (int i = 0; i < 7; i++) {
aeroStream << (double)0.0;
}
// flap_f8 数组需要10个double
for (int i = 0; i < 10; i++) {
aeroStream << (double)0.0;
}
// slat_f8 数组需要20个double
for (int i = 0; i < 20; i++) {
aeroStream << (double)0.0;
}
// spl_f8 数组需要20个double
for (int i = 0; i < 20; i++) {
aeroStream << (double)0.0;
}
// tnet_f8 数组需要4个double
for (int i = 0; i < 4; i++) {
aeroStream << (double)20000.0;
}
// kice_f8 数组需要20个double
for (int i = 0; i < 20; i++) {
aeroStream << (double)0.0;
}
// alt_agl
aeroStream << (double)1000.0;
// 更新数据包大小,确保不会溢出
if (aeroData.size() <= 255) {
aeroData[4] = aeroData.size();
} else {
LOG_WARNING("ATA04DataProcessor::SendUdpTestData: aeroData size exceeds byte limit: %d",
aeroData.size());
aeroData[4] = 255; // 设置为最大值
}
// 创建地面操作输入(GhInput)数据包
QByteArray ghData;
QDataStream ghStream(&ghData, QIODevice::WriteOnly);
ghStream.setByteOrder(QDataStream::LittleEndian);
ghStream.setVersion(QDataStream::Qt_6_0);
// 地面操作输入数据包头 (0x0b=从外部输入, 0x04=ATA04, 0x01=地面操作模型, 0x00=输入数据)
quint8 ghHeader[5] = {0x0b, 0x04, 0x01, 0x00, 0x00};
ghStream << ghHeader[0] << ghHeader[1] << ghHeader[2] << ghHeader[3] << ghHeader[4];
// 地面操作数据字段
ghStream << (quint8)0; // frz_l1
ghStream << (quint8)0; // chocks_l1
ghStream << (double)100.0; // alt_agl_f8
ghStream << (quint8)0; // frzflt_l1
ghStream << (double)0.0; // p_f8
ghStream << (double)0.0; // q_f8
ghStream << (double)0.0; // r_f8
ghStream << (double)0.0; // ug_f8
ghStream << (double)0.0; // vg_f8
ghStream << (double)0.0; // wg_f8
ghStream << (double)0.0; // blcg_f8
ghStream << (double)0.0; // bscg_f8
ghStream << (double)0.0; // wlcg_f8
ghStream << (quint8)0; // pb_active_l1
ghStream << (double)0.0; // pb_towforce_f8
// brake_torq_f8 数组 3x2
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
ghStream << (double)0.0;
}
}
// gear_f8 数组需要3个double
for (int i = 0; i < 3; i++) {
ghStream << (double)0.0;
}
// 另一个3个double的数组
for (int i = 0; i < 3; i++) {
ghStream << (double)0.0;
}
// gsteer_f8 数组需要10个double
for (int i = 0; i < 10; i++) {
ghStream << (double)0.0;
}
// tire_pres_f8 数组 3x2
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
ghStream << (double)30.0; // 30 psi的胎压
}
}
// 4个double数组
for (int i = 0; i < 4; i++) {
ghStream << (double)0.0;
}
ghStream << (quint8)0; // onjax_l1
// contdep_f8 数组需要7个double
for (int i = 0; i < 7; i++) {
ghStream << (double)0.0;
}
ghStream << (double)0.0; // thetag_f8
ghStream << (double)0.0; // phig_f8
ghStream << (qint32)0; // rwyrgh_i2
ghStream << (double)0.0; // rwyhdg_f8
ghStream << (quint8)0; // reset_braketemp_l1
ghStream << (quint8)0; // reset_tirepress_l1
ghStream << (double)20.0; // temp_c_f8
// brake_temp_f8 数组 3x2
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
ghStream << (double)50.0; // 50度的刹车温度
}
}
// tire_tburst_l1 数组 3x2
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
ghStream << (char)0;
}
}
// tire_tflat_l1 数组 3x2
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
ghStream << (char)0;
}
}
ghStream << (quint8)0; // brk_reset_tpres_l1
// rcon_ci_f8 数组需要14个double
for (int i = 0; i < 14; i++) {
ghStream << (double)0.0;
}
ghStream << (qint32)0; // gsteer_state_i4
ghStream << (quint8)0; // trim_active_l1
ghStream << (double)0.0; // phi_deg_f8
ghStream << (double)0.0; // theta_deg_f8
ghStream << (double)0.0; // psi_deg_f8
ghStream << (quint8)0; // resetint_l1
// 更新数据包大小,确保不会溢出
if (ghData.size() <= 255) {
ghData[4] = ghData.size();
} else {
LOG_WARNING("ATA04DataProcessor::SendUdpTestData: ghData size exceeds byte limit: %d",
ghData.size());
ghData[4] = 255; // 设置为最大值
}
// 创建重量平衡输入(WbInput)数据包
QByteArray wbData;
QDataStream wbStream(&wbData, QIODevice::WriteOnly);
wbStream.setByteOrder(QDataStream::LittleEndian);
wbStream.setVersion(QDataStream::Qt_6_0);
// 重量平衡输入数据包头 (0x0b=从外部输入, 0x04=ATA04, 0x02=重量平衡模型, 0x00=输入数据)
quint8 wbHeader[5] = {0x0b, 0x04, 0x02, 0x00, 0x00};
wbStream << wbHeader[0] << wbHeader[1] << wbHeader[2] << wbHeader[3] << wbHeader[4];
// 重量平衡数据字段
wbStream << (double)0.0; // theta_deg_f8
wbStream << (double)0.0; // phi_deg_f8
wbStream << (double)0.0; // psi_deg_f8
wbStream << (quint8)0; // gear_mode_l1
wbStream << (double)60000.0; // acset_gw_f8 (60000kg飞机重量)
wbStream << (double)25.0; // acset_cg_f8 (25%MAC重心位置)
// acset_tankfuel_f4 数组需要20个float
for (int i = 0; i < 20; i++) {
wbStream << (float)(i < 10 ? 1000.0 : 0.0); // 前10个油箱各1000kg
}
wbStream << (double)10000.0; // acset_totfuel_f8 (总油量10000kg)
wbStream << (double)50000.0; // acset_zfw_f8 (零油重50000kg)
wbStream << (double)24.0; // acset_zfwcg_f8 (零油重重心24%MAC)
// eng_efsep_l1 数组需要4个char
for (int i = 0; i < 4; i++) {
wbStream << (char)0;
}
// fuel_f8 数组需要20个double
for (int i = 0; i < 20; i++) {
wbStream << (double)(i < 10 ? 1000.0 : 0.0); // 前10个油箱各1000kg
}
wbStream << (double)0.0; // gear_avg_f8
// kice_f8 数组需要20个double
for (int i = 0; i < 20; i++) {
wbStream << (double)0.0;
}
wbStream << (quint8)0; // bycglim_l1
wbStream << (quint8)0; // bygwlim_l1
wbStream << (quint8)0; // frz_l1
wbStream << (quint8)0; // zcgfrz_l1
wbStream << (quint8)0; // zcgfrz_grfx_l1
wbStream << (quint8)0; // ycgfrz_l1
wbStream << (quint8)0; // inertfrz_l1
wbStream << (double)60000.0; // potreq_gw_f8
wbStream << (double)25.0; // potreq_gwcg_f8
// 更新数据包大小,确保不会溢出
if (wbData.size() <= 255) {
wbData[4] = wbData.size();
} else {
LOG_WARNING("ATA04DataProcessor::SendUdpTestData: wbData size exceeds byte limit: %d",
wbData.size());
wbData[4] = 255; // 设置为最大值
}
// 发送测试数据包
TriggerRTEvent("SendTestUDPData", QVariant::fromValue(aeroData));
TriggerRTEvent("SendTestUDPData", QVariant::fromValue(ghData));
TriggerRTEvent("SendTestUDPData", QVariant::fromValue(wbData));
}

View File

@ -59,6 +59,8 @@ private:
void SendWbHeartbeat();
void SendGhHeartbeat();
void SendUdpTestData();
};
Q_DECLARE_METATYPE(XNATA04DataProcessor)

View File

@ -89,25 +89,56 @@ void XNUDPService::HandleIncomingData()
d->udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
// 处理接收到的数据
if (datagram.size() <= 5 || datagram[0] != 0x0b || datagram[4] != datagram.size()) {
LOG_WARNING("Invalid UDP datagram received");
// 数据包头在第9个位置直接跳过前9个字节
if (datagram.size() <= 9) {
LOG_WARNING("Invalid size of UDP datagram received, size:%1", datagram.size());
continue;
}
if (datagram[1] == 0x04) {
if (datagram[2] == 0x00 && datagram[3] == 0x00) {
TriggerRTEvent("ATA04AeroInput", datagram);
// 创建一个新的数据包,去除前面的额外头信息
QByteArray actualData = datagram.mid(9);
// 使用处理后的数据
quint8 header = (quint8)actualData[0];
quint8 type = (quint8)actualData[1];
quint8 subType1 = (quint8)actualData[2];
quint8 subType2 = (quint8)actualData[3];
quint8 size = (quint8)actualData[4];
// 处理接收到的数据
if (actualData.size() <= 5) {
LOG_WARNING("Invalid size of UDP datagram received, size:%1", actualData.size());
continue;
}
if (header != 0x0b) {
LOG_WARNING("Invalid header of UDP datagram received, header:%1", header);
continue;
}
//如果数据包大小大于size,则截取size大小的数据
if (actualData.size() > size) {
actualData = actualData.mid(0, size);
} else if (actualData.size() < size) {
LOG_WARNING("Invalid size of UDP datagram received, size:%1, expected:%2",
actualData.size(), size);
continue;
}
if (type == 0x04) {
if (subType1 == 0x00 && subType2 == 0x00) {
TriggerRTEvent("ATA04AeroInput", actualData);
continue;
} else if (datagram[2] == 0x01 && datagram[3] == 0x00) {
TriggerRTEvent("ATA04GhInput", datagram);
} else if (subType1 == 0x01 && subType2 == 0x00) {
TriggerRTEvent("ATA04GhInput", actualData);
continue;
} else if (datagram[2] == 0x02 && datagram[3] == 0x00) {
TriggerRTEvent("ATA04WbInput", datagram);
} else if (subType1 == 0x02 && subType2 == 0x00) {
TriggerRTEvent("ATA04WbInput", actualData);
continue;
}
}
// TODO: 根据具体需求处理其它数据
TriggerRTEvent("ReceiveUDPData", datagram);
TriggerRTEvent("ReceiveUDPData", actualData);
}
}

View File

@ -0,0 +1,9 @@
{
"configurations": [
{
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}

View File

@ -0,0 +1,5 @@
{
"files.associations": {
"functional": "cpp"
}
}

View File

@ -0,0 +1,65 @@
cmake_minimum_required(VERSION 3.16)
project(XNUDPTestService LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#
if(DEFINED ENV{XNCore})
set(XNCore_PATH $ENV{XNCore})
else()
message(FATAL_ERROR "Environment variable XNCore is not set.")
endif()
# XNCore_PATH include
include_directories(${XNCore_PATH}/include)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Network Xml)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Network Xml)
add_library(XNUDPTestService SHARED
XNUDPTestService_global.h
XNUDPTestService.cpp
XNUDPTestService.h
XNUDPTestService_p.h
)
target_link_libraries(XNUDPTestService PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Xml
${XNCore_PATH}/lib/libXNCore.so
)
# Qt
get_target_property(QT_LIB_DIR Qt${QT_VERSION_MAJOR}::Core LOCATION)
get_filename_component(QT_LIB_DIR ${QT_LIB_DIR} DIRECTORY)
# rpath
set_target_properties(XNUDPTestService PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_RPATH "${QT_LIB_DIR}"
)
target_compile_definitions(XNUDPTestService PRIVATE XNUDPSERVICE_LIBRARY)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}/Services" CACHE PATH "Install path prefix" FORCE)
endif()
include(GNUInstallDirs)
install(TARGETS XNUDPTestService
BUNDLE DESTINATION .
LIBRARY DESTINATION .
RUNTIME DESTINATION .
)
#
file(GLOB CONFIG_FILE "*.scfg")
# 使 install
install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX})

View File

@ -0,0 +1,424 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 14.0.1, 2025-01-26T10:40:40. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{5b958118-2d32-49ab-8eab-9018ac74c7d6}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="qlonglong">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<value type="bool" key="AutoTest.ApplyFilter">false</value>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">5</value>
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ClangdSettings">
<value type="bool" key="blockIndexing">true</value>
<value type="bool" key="useGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 6.7.2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 6.7.2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt6.672.linux_gcc_64_kit</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="CMake.Build.Type">Debug</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Unix Makefiles
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
-DCMAKE_BUILD_TYPE:STRING=Debug</value>
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="CMake.Build.Type">Release</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Unix Makefiles
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
-DCMAKE_BUILD_TYPE:STRING=Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Unix Makefiles
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-RelWithDebInfo</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Unix Makefiles
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo</value>
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.4">
<value type="QString" key="CMake.Build.Type">MinSizeRel</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Unix Makefiles
-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
-DCMAKE_BUILD_TYPE:STRING=MinSizeRel</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/jin/E/MyCode/xnsim/XNModels/XNAerodynamics/build/Desktop_Qt_6_7_2-MinSizeRel</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">清除</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">5</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">部署</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">部署</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="qlonglong">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@ -0,0 +1,135 @@
#include "XNUDPTestService.h"
#include "XNUDPTestService_p.h"
#include <XNCore/XNServiceManager.h>
#include <XNCore/XNDDSManager.h>
#include <QFile>
#include <QDomDocument>
XN_DLL_INITIALIZE(XNUDPTestService)
XN_REGISTER_SERVICE_BEGIN_SERVICE(XNUDPTestService)
XN_REGISTER_SERVICE_END_SERVICE(XNUDPTestService)
XNUDPTestService::XNUDPTestService(QObject *parent)
: XNServiceObject(*new XNUDPTestServicePrivate(this), parent)
{
}
XNUDPTestService::~XNUDPTestService()
{
}
XNUDPTestService::XNUDPTestService(XNUDPTestServicePrivate &dd, QObject *parent)
: XNServiceObject(dd, parent)
{
}
void XNUDPTestService::OnInitialize()
{
Q_D(XNUDPTestService);
XNServiceObject::OnInitialize();
// 读取配置文件
QFile file(GetXmlPath());
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_WARNING("Failed to open config file:%1", GetXmlPath());
return;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
file.close();
LOG_WARNING("Failed to parse config file:%1", GetXmlPath());
return;
}
file.close();
// 读取UDP配置
QDomElement udpElement = doc.documentElement().firstChildElement("UDP");
if (!udpElement.isNull()) {
d->localPort = udpElement.firstChildElement("LocalPort").text().toUInt();
d->targetHost = udpElement.firstChildElement("TargetHost").text();
d->targetPort = udpElement.firstChildElement("TargetPort").text().toUInt();
} else {
LOG_WARNING("UDP configuration not found, using default values");
d->localPort = 12345;
d->targetHost = "127.0.0.1";
d->targetPort = 54321;
}
}
void XNUDPTestService::OnPrepareForExecute()
{
Q_D(XNUDPTestService);
XNServiceObject::OnPrepareForExecute();
// 初始化UDP socket
d->udpSocket = new QUdpSocket(this);
// 绑定本地端口
if (!d->udpSocket->bind(QHostAddress::Any, d->localPort)) {
LOG_WARNING("UDP socket bind failed on port:%1", d->localPort);
return;
}
// 连接UDP socket的信号
connect(d->udpSocket, &QUdpSocket::readyRead, this, &XNUDPTestService::HandleIncomingData);
RegisterRTEventHandler("SendTestUDPData",
std::bind(&XNUDPTestService::SendData, this, std::placeholders::_1));
}
void XNUDPTestService::HandleIncomingData()
{
Q_D(XNUDPTestService);
return;
while (d->udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(d->udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
d->udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
// 处理接收到的数据
if (datagram.size() <= 5 || datagram[0] != 0x0b || datagram[4] != datagram.size()) {
LOG_WARNING("Invalid UDP datagram received");
continue;
}
if (datagram[1] == 0x04) {
if (datagram[2] == 0x00 && datagram[3] == 0x00) {
TriggerRTEvent("ATA04AeroInput", datagram);
continue;
} else if (datagram[2] == 0x01 && datagram[3] == 0x00) {
TriggerRTEvent("ATA04GhInput", datagram);
continue;
} else if (datagram[2] == 0x02 && datagram[3] == 0x00) {
TriggerRTEvent("ATA04WbInput", datagram);
continue;
}
}
// TODO: 根据具体需求处理其它数据
//TriggerRTEvent("ReceiveUDPData", datagram);
}
}
void XNUDPTestService::SendData(const QVariant &data)
{
Q_D(XNUDPTestService);
if (!d->udpSocket) {
LOG_WARNING("UDP socket not initialized");
return;
}
// 将QVariant转换为字节数组
QByteArray datagram;
QDataStream stream(&datagram, QIODevice::WriteOnly);
stream << data;
// 发送数据
qint64 bytesSent =
d->udpSocket->writeDatagram(datagram, QHostAddress(d->targetHost), d->targetPort);
if (bytesSent == -1) {
LOG_WARNING("Failed to send UDP datagram:%1", d->udpSocket->errorString());
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "XNUDPTestService_global.h"
#include <XNCore/XNServiceObject.h>
#include <QVariant>
class XNUDPTestServicePrivate;
class XNUDPTESTSERVICE_EXPORT XNUDPTestService : public XNServiceObject
{
Q_OBJECT
Q_DISABLE_COPY(XNUDPTestService)
Q_DECLARE_PRIVATE(XNUDPTestService)
XN_DECLARE_DDS_SERVICE()
public:
explicit XNUDPTestService(QObject *parent = nullptr);
virtual ~XNUDPTestService();
protected:
XNUDPTestService(XNUDPTestServicePrivate &dd, QObject *parent = nullptr);
public slots:
virtual void OnInitialize() override;
virtual void OnPrepareForExecute() override;
void HandleIncomingData();
public:
void SendData(const QVariant &data);
};
Q_DECLARE_METATYPE(XNUDPTestService)

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Service>
<Name>XNUDPTestService</Name>
<Description>UDP通信服务</Description>
<Author>Jin</Author>
<Version>1.0.0</Version>
<CreateTime>2025-02-04 10:00:00</CreateTime>
<ChangeTime>2025-02-04 10:00:00</ChangeTime>
<CommandList>
<Command Name="TestCmd" Description="Test" Call="TestCall"/>
</CommandList>
<UDP>
<LocalPort>54321</LocalPort>
<TargetHost>127.0.0.1</TargetHost>
<TargetPort>12345</TargetPort>
</UDP>
</Service>

View File

@ -0,0 +1,12 @@
#ifndef XNUDPTESTSERVICE_GLOBAL_H
#define XNUDPTESTSERVICE_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(XNUDPTESTSERVICE_LIBRARY)
# define XNUDPTESTSERVICE_EXPORT Q_DECL_EXPORT
#else
# define XNUDPTESTSERVICE_EXPORT Q_DECL_IMPORT
#endif
#endif // XNUDPTESTSERVICE_GLOBAL_H

View File

@ -0,0 +1,17 @@
#pragma once
#include <XNCore/XNServiceObject_p.h>
#include <QUdpSocket>
#include <QString>
class XNUDPTestServicePrivate : public XNServiceObjectPrivate
{
public:
Q_DECLARE_PUBLIC(XNUDPTestService)
XNUDPTestServicePrivate(XNUDPTestService *q) : XNServiceObjectPrivate(q) {}
QUdpSocket *udpSocket{nullptr};
QString targetHost;
quint16 targetPort{0};
quint16 localPort{0};
};

View File

@ -2,12 +2,225 @@ class DataMonitor extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.currentMode = 'udp'; // 默认显示UDP模式
this.udpPort = 54321; // 默认UDP端口
this.udpIp = '127.0.0.1'; // 默认监听所有接口
this.isMonitoring = false; // 监控状态
this.udpData = []; // 存储接收到的UDP数据
// UDP数据注入默认值
this.injectIp = '127.0.0.1';
this.injectPort = 12345;
this.injectData = '{"message": "测试数据"}';
}
connectedCallback() {
this.render();
}
switchMode(mode) {
this.currentMode = mode;
this.render();
}
async startMonitoring() {
if (this.isMonitoring) return;
try {
const response = await fetch('/api/udp-monitor/start', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
port: this.udpPort,
ip: this.udpIp
}),
});
const data = await response.json();
if (data.success) {
this.isMonitoring = true;
this.updateMonitoringStatus();
this.setupDataFetch();
} else {
this.showError(data.error || '启动监控失败');
}
} catch (error) {
this.showError('无法连接到服务器');
console.error('启动UDP监控失败:', error);
}
}
async stopMonitoring() {
if (!this.isMonitoring) return;
try {
const response = await fetch('/api/udp-monitor/stop', {
method: 'POST',
});
const data = await response.json();
if (data.success) {
this.isMonitoring = false;
this.updateMonitoringStatus();
if (this.dataFetchInterval) {
clearInterval(this.dataFetchInterval);
this.dataFetchInterval = null;
}
} else {
this.showError(data.error || '停止监控失败');
}
} catch (error) {
this.showError('无法连接到服务器');
console.error('停止UDP监控失败:', error);
}
}
async injectUdpData() {
try {
// 验证数据格式
let parsedData;
try {
parsedData = JSON.parse(this.injectData);
} catch (e) {
this.showError('数据格式无效请输入有效的JSON');
return;
}
const response = await fetch('/api/udp-monitor/inject', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
targetIp: this.injectIp,
targetPort: this.injectPort,
data: parsedData
}),
});
const data = await response.json();
if (data.success) {
this.showSuccess('数据已成功发送');
} else {
this.showError(data.error || '发送数据失败');
}
} catch (error) {
this.showError('无法连接到服务器');
console.error('发送UDP数据失败:', error);
}
}
setupDataFetch() {
// 清除可能存在的之前的定时器
if (this.dataFetchInterval) {
clearInterval(this.dataFetchInterval);
}
// 每秒拉取一次新数据
this.dataFetchInterval = setInterval(async () => {
try {
const response = await fetch('/api/udp-monitor/data');
const data = await response.json();
if (data.success && data.data) {
this.updateDataDisplay(data.data);
}
} catch (error) {
console.error('获取UDP数据失败:', error);
}
}, 1000);
}
updateDataDisplay(newData) {
if (!newData || newData.length === 0) return;
// 更新数据并限制显示的数据条数
this.udpData = [...this.udpData, ...newData].slice(-100);
const dataContainer = this.shadowRoot.querySelector('.data-container');
if (!dataContainer) return;
dataContainer.innerHTML = this.udpData.map(item => {
return `<div class="data-item">
<span class="timestamp">${new Date(item.timestamp).toLocaleTimeString()}</span>
<span class="source">${item.source}</span>
<span class="data">${this.formatData(item.data)}</span>
</div>`;
}).join('');
// 自动滚动到底部
dataContainer.scrollTop = dataContainer.scrollHeight;
}
formatData(data) {
// 简单显示为字符串,真实实现可能更复杂
if (typeof data === 'object') {
return JSON.stringify(data);
}
return data;
}
updateMonitoringStatus() {
const statusLabel = this.shadowRoot.querySelector('.status-label');
const startButton = this.shadowRoot.querySelector('#start-monitoring');
const stopButton = this.shadowRoot.querySelector('#stop-monitoring');
const portInput = this.shadowRoot.querySelector('#udp-port');
const ipInput = this.shadowRoot.querySelector('#udp-ip');
if (statusLabel) {
statusLabel.textContent = this.isMonitoring ? '监控中' : '未监控';
statusLabel.className = `status-label ${this.isMonitoring ? 'active' : 'inactive'}`;
}
if (startButton) {
startButton.disabled = this.isMonitoring;
}
if (stopButton) {
stopButton.disabled = !this.isMonitoring;
}
if (portInput) {
portInput.disabled = this.isMonitoring;
}
if (ipInput) {
ipInput.disabled = this.isMonitoring;
}
}
showError(message) {
const errorElement = this.shadowRoot.querySelector('.error-message');
if (errorElement) {
errorElement.textContent = message;
errorElement.style.display = 'block';
errorElement.className = 'message-box error-message';
// 3秒后自动隐藏错误消息
setTimeout(() => {
errorElement.style.display = 'none';
}, 3000);
}
}
showSuccess(message) {
const successElement = this.shadowRoot.querySelector('.success-message');
if (successElement) {
successElement.textContent = message;
successElement.style.display = 'block';
// 3秒后自动隐藏成功消息
setTimeout(() => {
successElement.style.display = 'none';
}, 3000);
}
}
render() {
this.shadowRoot.innerHTML = `
<style>
@ -26,30 +239,428 @@ class DataMonitor extends HTMLElement {
padding: 16px;
height: 100%;
box-sizing: border-box;
}
.monitor-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #e0e0e0;
flex-direction: column;
}
.monitor-title {
font-size: 18px;
.mode-switcher {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.mode-button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.mode-button.active {
background-color: #1890ff;
color: white;
font-weight: bold;
}
.mode-button:not(.active) {
background-color: #f0f0f0;
color: #333;
}
.mode-content {
flex-grow: 1;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 16px;
display: flex;
flex-direction: column;
}
.udp-content {
display: flex;
gap: 16px;
height: 100%;
}
.monitor-section, .inject-section {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.section-divider {
width: 1px;
background-color: #e0e0e0;
margin: 0 8px;
}
.section-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.mode-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
color: #333;
}
.placeholder-content {
color: #888;
font-style: italic;
}
.control-panel {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
}
.port-input, .ip-input {
display: flex;
align-items: center;
}
.port-input label, .ip-input label {
margin-right: 8px;
font-size: 14px;
white-space: nowrap;
}
.port-input input, .ip-input input {
padding: 6px 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
}
.port-input input {
width: 80px;
}
.ip-input input {
width: 140px;
}
.action-button {
padding: 6px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.action-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.start-button {
background-color: #52c41a;
color: white;
}
.stop-button {
background-color: #f5222d;
color: white;
}
.inject-button {
background-color: #1890ff;
color: white;
}
.status-container {
display: flex;
align-items: center;
margin-left: auto;
}
.status-label {
font-size: 14px;
padding: 4px 8px;
border-radius: 10px;
}
.status-label.active {
background-color: #e6f7ff;
color: #1890ff;
}
.status-label.inactive {
background-color: #f5f5f5;
color: #999;
}
.message-box {
margin-top: 8px;
font-size: 14px;
padding: 8px 12px;
border-radius: 4px;
display: none;
}
.error-message {
background-color: #fff2f0;
border: 1px solid #ffccc7;
color: #f5222d;
}
.success-message {
background-color: #f6ffed;
border: 1px solid #b7eb8f;
color: #52c41a;
}
.data-view {
flex-grow: 1;
margin-top: 16px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.data-container {
flex-grow: 1;
border: 1px solid #f0f0f0;
border-radius: 4px;
padding: 8px;
overflow-y: auto;
background-color: #fafafa;
font-family: monospace;
}
.data-item {
padding: 4px 0;
border-bottom: 1px solid #f0f0f0;
display: flex;
}
.data-item .timestamp {
color: #888;
margin-right: 8px;
min-width: 80px;
}
.data-item .source {
color: #1890ff;
margin-right: 8px;
min-width: 120px;
}
.data-item .data {
color: #333;
word-break: break-all;
}
.data-input {
margin-top: 16px;
}
.data-input label {
display: block;
margin-bottom: 8px;
font-size: 14px;
}
.data-input textarea {
width: 100%;
height: 120px;
padding: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
resize: vertical;
font-family: monospace;
font-size: 14px;
}
.inject-actions {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
</style>
<div class="monitor-container">
<div class="monitor-header">
<div class="monitor-title">数据监控</div>
<div class="mode-switcher">
<button class="mode-button ${this.currentMode === 'udp' ? 'active' : ''}" id="udp-mode">UDP监控</button>
<button class="mode-button ${this.currentMode === 'fastdds' ? 'active' : ''}" id="fastdds-mode">FastDDS监控</button>
</div>
<div class="mode-content">
${this.currentMode === 'udp'
? `<div class="mode-title">UDP数据监控</div>
<div class="udp-content">
<!-- 左侧UDP数据监控 -->
<div class="monitor-section">
<div class="section-title">UDP数据监控</div>
<div class="control-panel">
<div class="ip-input">
<label for="udp-ip">监听IP:</label>
<input type="text" id="udp-ip" value="${this.udpIp}"
${this.isMonitoring ? 'disabled' : ''} placeholder="0.0.0.0">
</div>
<div class="port-input">
<label for="udp-port">监听端口:</label>
<input type="number" id="udp-port" min="1024" max="65535" value="${this.udpPort}"
${this.isMonitoring ? 'disabled' : ''}>
</div>
<button id="start-monitoring" class="action-button start-button"
${this.isMonitoring ? 'disabled' : ''}>开始监控</button>
<button id="stop-monitoring" class="action-button stop-button"
${!this.isMonitoring ? 'disabled' : ''}>停止监控</button>
<div class="status-container">
<span class="status-label ${this.isMonitoring ? 'active' : 'inactive'}">
${this.isMonitoring ? '监控中' : '未监控'}
</span>
</div>
</div>
<div class="message-box error-message"></div>
<div class="data-view">
<div class="data-container"></div>
</div>
</div>
<!-- 分隔线 -->
<div class="section-divider"></div>
<!-- 右侧UDP数据注入 -->
<div class="inject-section">
<div class="section-title">UDP数据注入</div>
<div class="control-panel">
<div class="ip-input">
<label for="inject-ip">目标IP:</label>
<input type="text" id="inject-ip" value="${this.injectIp}" placeholder="127.0.0.1">
</div>
<div class="port-input">
<label for="inject-port">目标端口:</label>
<input type="number" id="inject-port" min="1024" max="65535" value="${this.injectPort}">
</div>
</div>
<div class="data-input">
<label for="inject-data">数据内容 (JSON格式):</label>
<textarea id="inject-data">${this.injectData}</textarea>
</div>
<div class="message-box success-message"></div>
<div class="inject-actions">
<button id="inject-data-btn" class="action-button inject-button">发送数据</button>
</div>
</div>
</div>`
: `<div class="mode-title">FastDDS数据监控</div>
<div class="placeholder-content">FastDDS数据监控内容待实现</div>`}
</div>
<div>数据监控组件内容待实现</div>
</div>
`;
// 添加切换模式的事件监听
this.shadowRoot.getElementById('udp-mode').addEventListener('click', () => this.switchMode('udp'));
this.shadowRoot.getElementById('fastdds-mode').addEventListener('click', () => this.switchMode('fastdds'));
// 如果是UDP模式添加控制按钮的事件监听
if (this.currentMode === 'udp') {
// 监控部分事件监听
// IP输入事件
const ipInput = this.shadowRoot.getElementById('udp-ip');
if (ipInput) {
ipInput.addEventListener('change', (e) => {
const value = e.target.value.trim();
// 简单的IP地址验证可以接受0.0.0.0或具体IP
if (value === '0.0.0.0' || /^(\d{1,3}\.){3}\d{1,3}$/.test(value)) {
this.udpIp = value;
} else {
e.target.value = this.udpIp;
this.showError('请输入有效的IP地址');
}
});
}
// 端口输入事件
const portInput = this.shadowRoot.getElementById('udp-port');
if (portInput) {
portInput.addEventListener('change', (e) => {
const value = parseInt(e.target.value, 10);
if (value >= 1024 && value <= 65535) {
this.udpPort = value;
} else {
e.target.value = this.udpPort;
this.showError('端口号必须在1024-65535之间');
}
});
}
// 开始监控按钮
const startButton = this.shadowRoot.getElementById('start-monitoring');
if (startButton) {
startButton.addEventListener('click', () => this.startMonitoring());
}
// 停止监控按钮
const stopButton = this.shadowRoot.getElementById('stop-monitoring');
if (stopButton) {
stopButton.addEventListener('click', () => this.stopMonitoring());
}
// 数据注入部分事件监听
// 注入IP输入事件
const injectIpInput = this.shadowRoot.getElementById('inject-ip');
if (injectIpInput) {
injectIpInput.addEventListener('change', (e) => {
const value = e.target.value.trim();
if (/^(\d{1,3}\.){3}\d{1,3}$/.test(value)) {
this.injectIp = value;
} else {
e.target.value = this.injectIp;
this.showError('请输入有效的IP地址');
}
});
}
// 注入端口输入事件
const injectPortInput = this.shadowRoot.getElementById('inject-port');
if (injectPortInput) {
injectPortInput.addEventListener('change', (e) => {
const value = parseInt(e.target.value, 10);
if (value >= 1024 && value <= 65535) {
this.injectPort = value;
} else {
e.target.value = this.injectPort;
this.showError('端口号必须在1024-65535之间');
}
});
}
// 注入数据输入事件
const injectDataInput = this.shadowRoot.getElementById('inject-data');
if (injectDataInput) {
injectDataInput.addEventListener('change', (e) => {
this.injectData = e.target.value;
});
}
// 发送数据按钮
const injectButton = this.shadowRoot.getElementById('inject-data-btn');
if (injectButton) {
injectButton.addEventListener('click', () => this.injectUdpData());
}
}
}
}

View File

@ -0,0 +1,257 @@
const express = require('express');
const router = express.Router();
const dgram = require('dgram');
// 全局变量存储UDP服务器实例和接收到的数据
let udpServer = null;
let udpData = [];
let isMonitoring = false;
let currentPort = null;
let currentIp = null;
// 开始UDP监控
router.post('/start', (req, res) => {
try {
const { port, ip } = req.body;
// 验证端口参数
if (!port || port < 1024 || port > 65535) {
return res.status(400).json({
success: false,
error: '端口号必须在1024-65535之间'
});
}
// 验证IP参数
if (!ip) {
return res.status(400).json({
success: false,
error: 'IP地址不能为空'
});
}
// 如果已经在监控,先停止之前的监控
if (isMonitoring) {
stopUdpServer();
}
// 创建UDP服务器
udpServer = dgram.createSocket('udp4');
currentPort = port;
currentIp = ip;
// 清空之前的数据
udpData = [];
// 监听错误事件
udpServer.on('error', (err) => {
console.error(`UDP服务器错误:`, err);
isMonitoring = false;
udpServer.close();
udpServer = null;
});
// 监听消息事件
udpServer.on('message', (msg, rinfo) => {
// 将收到的数据添加到数据队列
try {
let processedData;
// 尝试将数据解析为JSON
try {
processedData = JSON.parse(msg.toString());
} catch (e) {
// 如果不是JSON则保存为字符串
processedData = msg.toString();
}
// 将数据添加到队列
udpData.push({
timestamp: Date.now(),
source: `${rinfo.address}:${rinfo.port}`,
data: processedData
});
// 限制数据队列大小最多保存1000条记录
if (udpData.length > 1000) {
udpData = udpData.slice(-1000);
}
} catch (error) {
console.error('处理UDP数据时出错:', error);
}
});
// 监听监听事件
udpServer.on('listening', () => {
const address = udpServer.address();
console.log(`UDP数据监控已启动在 ${address.address}:${address.port}`);
isMonitoring = true;
});
// 绑定IP和端口
udpServer.bind(port, ip);
res.json({
success: true,
message: `UDP监控已在 ${ip}:${port} 上启动`
});
} catch (error) {
console.error('启动UDP监控失败:', error);
res.status(500).json({
success: false,
error: '启动UDP监控失败: ' + error.message
});
}
});
// 停止UDP监控
router.post('/stop', (req, res) => {
try {
if (!isMonitoring) {
return res.json({
success: true,
message: '没有正在运行的UDP监控'
});
}
stopUdpServer();
res.json({
success: true,
message: 'UDP监控已停止'
});
} catch (error) {
console.error('停止UDP监控失败:', error);
res.status(500).json({
success: false,
error: '停止UDP监控失败: ' + error.message
});
}
});
// 注入UDP数据
router.post('/inject', (req, res) => {
try {
const { targetIp, targetPort, data } = req.body;
// 验证参数
if (!targetIp) {
return res.status(400).json({
success: false,
error: '目标IP地址不能为空'
});
}
if (!targetPort || targetPort < 1024 || targetPort > 65535) {
return res.status(400).json({
success: false,
error: '目标端口号必须在1024-65535之间'
});
}
if (!data) {
return res.status(400).json({
success: false,
error: '数据内容不能为空'
});
}
// 创建临时UDP客户端
const client = dgram.createSocket('udp4');
// 将数据对象转换为JSON字符串
const message = JSON.stringify(data);
// 发送数据
client.send(message, targetPort, targetIp, (err) => {
// 关闭客户端
client.close();
if (err) {
console.error('发送UDP数据失败:', err);
return res.status(500).json({
success: false,
error: '发送UDP数据失败: ' + err.message
});
}
console.log(`已发送UDP数据到 ${targetIp}:${targetPort}`);
res.json({
success: true,
message: `数据已成功发送到 ${targetIp}:${targetPort}`
});
});
} catch (error) {
console.error('发送UDP数据失败:', error);
res.status(500).json({
success: false,
error: '发送UDP数据失败: ' + error.message
});
}
});
// 获取UDP监控数据
router.get('/data', (req, res) => {
try {
// 创建一个新数组来保存返回的数据
const dataToSend = [...udpData];
// 清空数据队列
udpData = [];
res.json({
success: true,
data: dataToSend,
isMonitoring,
port: currentPort,
ip: currentIp
});
} catch (error) {
console.error('获取UDP监控数据失败:', error);
res.status(500).json({
success: false,
error: '获取UDP监控数据失败: ' + error.message
});
}
});
// 获取当前监控状态
router.get('/status', (req, res) => {
res.json({
success: true,
isMonitoring,
port: currentPort,
ip: currentIp
});
});
// 辅助函数停止UDP服务器
function stopUdpServer() {
if (udpServer) {
try {
udpServer.close();
console.log('UDP监控已停止');
} catch (error) {
console.error('关闭UDP服务器时出错:', error);
}
udpServer = null;
isMonitoring = false;
currentPort = null;
currentIp = null;
}
}
// 当应用程序关闭时确保UDP服务器也关闭
process.on('exit', stopUdpServer);
process.on('SIGINT', () => {
stopUdpServer();
process.exit(0);
});
module.exports = router;

View File

@ -17,6 +17,7 @@ const idlRoutes = require('./routes/idl');
const projectModelRoutes = require('./routes/project-model');
const ataChaptersRoutes = require('./routes/model-dev');
const simulationRoutes = require('./routes/run-simulation');
const udpMonitorRoutes = require('./routes/udp-monitor');
const app = express();
const PORT = process.env.PORT || 3000;
@ -64,6 +65,7 @@ app.use('/api/idl', idlRoutes);
app.use('/api', projectModelRoutes);
app.use('/api', ataChaptersRoutes);
app.use('/api', simulationRoutes);
app.use('/api/udp-monitor', udpMonitorRoutes);
// 主页路由
app.get('/', (req, res) => {