feat: Read engine RPM from simulator and transmit

This commit is contained in:
Lars Toenning
2026-06-20 16:00:46 +02:00
parent dd6f83cbc5
commit ef3497b778
15 changed files with 88 additions and 24 deletions

View File

@@ -11,7 +11,8 @@ SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAircraftEngine)
namespace swift::misc::aviation
{
CAircraftEngine::CAircraftEngine(int number, bool on) : m_number(number), m_on(on)
CAircraftEngine::CAircraftEngine(int number, bool on, int engineRpmPct)
: m_number(number), m_on(on), m_rpmPct(std::max(0, engineRpmPct))
{
Q_ASSERT_X(number > 0, "CAircraftEngine", "Engine numbers have to be >= 1");
}
@@ -22,6 +23,8 @@ namespace swift::misc::aviation
m_number = number;
}
void CAircraftEngine::setEngineRpmPct(int percentage) { m_rpmPct = std::max(0, percentage); }
QString CAircraftEngine::convertToQString(bool i18n) const
{
Q_UNUSED(i18n);

View File

@@ -26,7 +26,7 @@ namespace swift::misc::aviation
//! Constructor
//! \remark numbers are 1 based!
CAircraftEngine(int number, bool on);
CAircraftEngine(int number, bool on, int engineRpmPct);
//! Get engine number
//! \remark numbers are 1 based!
@@ -42,17 +42,27 @@ namespace swift::misc::aviation
//! Set to on/off
void setOn(bool on) { m_on = on; }
//! Set engine RPM percentage (0..100+)
//! \remark Percentage can be larger 100 if for example using afterburn
void setEngineRpmPct(int percentage);
//! Get engine RPM percentage (0..100+)
//! \remark Percentage can be larger 100 if for example using afterburn
int getEngineRpmPct() const { return m_rpmPct; }
//! \copydoc swift::misc::mixin::String::toQString
QString convertToQString(bool i18n = false) const;
private:
int m_number = 1;
bool m_on = true;
int m_rpmPct = 0;
SWIFT_METACLASS(
CAircraftEngine,
SWIFT_METAMEMBER(number, 0, DisabledForJson),
SWIFT_METAMEMBER(on));
SWIFT_METAMEMBER(on),
SWIFT_METAMEMBER_NAMED(rpmPct, "rpm_pct"));
};
} // namespace swift::misc::aviation

View File

@@ -10,12 +10,12 @@ SWIFT_DEFINE_SEQUENCE_MIXINS(swift::misc::aviation, CAircraftEngine, CAircraftEn
namespace swift::misc::aviation
{
CAircraftEngineList::CAircraftEngineList(std::initializer_list<bool> enginesOnOff)
CAircraftEngineList::CAircraftEngineList(std::initializer_list<std::pair<bool, int>> enginesOnOff)
{
int no = 1; // engines 1 based
for (bool it : enginesOnOff)
for (const auto [on, engineRpmPct] : enginesOnOff)
{
CAircraftEngine engine(no++, it);
CAircraftEngine engine(no++, on, engineRpmPct);
this->push_back(engine);
}
}
@@ -60,16 +60,35 @@ namespace swift::misc::aviation
}
}
void CAircraftEngineList::initEngines(int engineNumber, bool on)
void CAircraftEngineList::initEngines(int engineNumber, bool on, int engineRpmPercentage)
{
this->clear();
for (int e = 0; e < engineNumber; e++)
{
const CAircraftEngine engine(e + 1, on);
const CAircraftEngine engine(e + 1, on, engineRpmPercentage);
this->push_back(engine);
}
}
void CAircraftEngineList::setEngineRpmPct(int engineNumber, int percentage)
{
Q_ASSERT(engineNumber > 0);
for (CAircraftEngine &engine : *this)
{
if (engine.getNumber() == engineNumber)
{
engine.setEngineRpmPct(percentage);
break;
}
}
}
int CAircraftEngineList::getEngineRpmPct(int engineNumber) const
{
Q_ASSERT(engineNumber > 0);
return this->getEngine(engineNumber).getEngineRpmPct();
}
bool CAircraftEngineList::isAnyEngineOn() const { return this->contains(&CAircraftEngine::isOn, true); }
QJsonObject CAircraftEngineList::toJson() const

View File

@@ -35,8 +35,8 @@ namespace swift::misc::aviation
//! Default constructor.
CAircraftEngineList() = default;
//! Construct by bool values for engines 1,2 ...
CAircraftEngineList(std::initializer_list<bool> enginesOnOff);
//! Construct by bool (on/off) and RPM percentage values for engines 1,2 ...
CAircraftEngineList(std::initializer_list<std::pair<bool, int>> enginesOnOff);
//! Construct from a base class object.
CAircraftEngineList(const CSequence<CAircraftEngine> &other);
@@ -57,11 +57,19 @@ namespace swift::misc::aviation
void setEngines(const CAircraftEngine &engine, int engineNumber);
//! Init some engines
void initEngines(int engineNumber, bool on);
void initEngines(int engineNumber, bool on, int engineRpmPercentage);
//! Is any engine on?
bool isAnyEngineOn() const;
//! Set engine RPM percentage (0..100+)
//! \remark Percentage can be larger 100 if for example using afterburn
void setEngineRpmPct(int engineNumber, int percentage);
//! Get engine RPM percentage (0..100+)
//! \remark Percentage can be larger 100 if for example using afterburn
int getEngineRpmPct(int engineNumber) const;
//! \copydoc swift::misc::mixin::JsonByMetaClass::toJson
QJsonObject toJson() const;

View File

@@ -494,7 +494,8 @@ namespace swift::misc::simulation
do {
// set some reasonable values
const bool isOnGround = situation.isOnGround();
engines.initEngines(engineCount, !isOnGround || situation.isMoving());
engines.initEngines(engineCount, !isOnGround || situation.isMoving(),
(!isOnGround || situation.isMoving()) ? 100 : 0);
parts.setGearDown(isOnGround);
parts.setSpoilersOut(false);
parts.setEngines(engines);
@@ -530,7 +531,7 @@ namespace swift::misc::simulation
if (details) { *details = QStringLiteral("no ground info"); }
// no idea if on ground or not
engines.initEngines(engineCount, true);
engines.initEngines(engineCount, true, 100);
parts.setEngines(engines);
parts.setGearDown(true);
parts.setSpoilersOut(false);

View File

@@ -89,7 +89,7 @@ namespace swift::misc::test
ok = pingCompare(lights, lightsPing, out, verbose, errors);
if (verbose) { out << "Pinged lights via interface" << errorInfo(ok) << Qt::endl; }
const CAircraftEngine engine(2, false);
const CAircraftEngine engine(2, false, 0);
const CAircraftEngine enginePing = testServiceInterface.pingAircraftEngine(engine);
ok = pingCompare(engine, enginePing, out, verbose, errors);
if (verbose) { out << "Pinged engine via interface" << errorInfo(ok) << Qt::endl; }

View File

@@ -280,8 +280,8 @@ namespace swift::simplugin::flightgear
{
// Engine number start counting at 1
// We consider the engine running when N1 is bigger than 5 %
CAircraftEngine engine { engineNumber + 1,
m_flightgearData.enginesN1Percentage.at(engineNumber) > 5.0 };
CAircraftEngine engine { engineNumber + 1, m_flightgearData.enginesN1Percentage.at(engineNumber) > 5.0,
static_cast<int>(m_flightgearData.enginesN1Percentage.at(engineNumber)) };
engines.push_back(engine);
}

View File

@@ -167,6 +167,14 @@ namespace swift::simplugin::fsxcommon
"GENERAL ENG COMBUSTION:3", "Bool");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
"GENERAL ENG COMBUSTION:4", "Bool");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
"GENERAL ENG PCT MAX RPM:1", "percent");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
"GENERAL ENG PCT MAX RPM:2", "percent");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
"GENERAL ENG PCT MAX RPM:3", "percent");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
"GENERAL ENG PCT MAX RPM:4", "percent");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD X",
"Feet per second");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD Y",

View File

@@ -70,15 +70,19 @@ namespace swift::simplugin::fsxcommon
double engine3Combustion; //!< Engine 3 combustion flag
double engine4Combustion; //!< Engine 4 combustion flag
// 38
double engine1RpmPct; //!< Engine 1 RPM [%]
double engine2RpmPct; //!< Engine 2 RPM [%]
double engine3RpmPct; //!< Engine 3 RPM [%]
double engine4RpmPct; //!< Engine 4 RPM [%]g
double velocityWorldX; //!< Velocity World X
double velocityWorldY; //!< Velocity World Y
double velocityWorldZ; //!< Velocity World Z
double rotationVelocityBodyX; //!< Rotation Velocity Body X
double rotationVelocityBodyY; //!< Rotation Velocity Body Y
double rotationVelocityBodyZ; //!< Rotation Velocity Body Z
// 44
// 48
double altitudeCalibratedFt; //!< Altitude without temperature effect (ft, FS2020)
// 45
// 49
};
//! Data struct of aircraft position

View File

@@ -743,10 +743,18 @@ namespace swift::simplugin::fsxcommon
dtb(simulatorOwnAircraft.engine2Combustion),
dtb(simulatorOwnAircraft.engine3Combustion),
dtb(simulatorOwnAircraft.engine4Combustion) };
const QList<double> powerList { simulatorOwnAircraft.engine1RpmPct, simulatorOwnAircraft.engine2RpmPct,
simulatorOwnAircraft.engine3RpmPct, simulatorOwnAircraft.engine4RpmPct };
for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
{
engines.push_back(CAircraftEngine(index + 1, helperList.value(index, true)));
// this is a bit of a guess, but it seems that idle is around 30% in the sim, so
// I use that as 0% for better resolution
// because we read "GENERAL ENG PCT MAX RPM" and send "GENERAL ENG THROTTLE LEVER POSITION"
const double factor = 30.0;
double engineRpm = (powerList.value(index, 0) - factor) * 100 / (100 - factor);
if (engineRpm < 0) engineRpm = 0;
engines.push_back(CAircraftEngine(index + 1, helperList.value(index, false), engineRpm));
}
const CAircraftParts parts(lights, dtb(simulatorOwnAircraft.gearHandlePosition),

View File

@@ -245,7 +245,7 @@ namespace swift::simplugin::fsxcommon
{
case CSimConnectDefinitions::RequestOwnAircraft:
{
static_assert(sizeof(DataDefinitionOwnAircraft) == 45 * sizeof(double),
static_assert(sizeof(DataDefinitionOwnAircraft) == 49 * sizeof(double),
"DataDefinitionOwnAircraft has an incorrect size.");
const DataDefinitionOwnAircraft *ownAircaft =
reinterpret_cast<const DataDefinitionOwnAircraft *>(&pObjData->dwData);

View File

@@ -402,7 +402,8 @@ namespace swift::simplugin::xplane
// Engine number start counting at 1
// We consider the engine running when N1 is bigger than 5 %
const CAircraftEngine engine { engineNumber + 1,
m_xplaneData.enginesN1Percentage.at(engineNumber) > 5.0 };
m_xplaneData.enginesN1Percentage.at(engineNumber) > 5.0,
static_cast<int>(m_xplaneData.enginesN1Percentage.at(engineNumber)) };
engines.push_back(engine);
}

View File

@@ -77,7 +77,7 @@ namespace MiscTest
{
const CAircraftLights lights = CAircraftLights::allLightsOn();
CAircraftEngineList engines;
engines.initEngines(4, true);
engines.initEngines(4, true, 100);
const bool onGround = true;
CAircraftParts ap(lights, true, 0, false, engines, onGround);
return ap;

View File

@@ -204,7 +204,8 @@ namespace MiscTest
CAircraftParts CTestInterpolatorLinear::getTestParts(int number, qint64 ts, qint64 deltaT)
{
CAircraftLights l(true, false, true, false, true, false);
CAircraftEngineList e({ CAircraftEngine(1, true), CAircraftEngine(2, false), CAircraftEngine(3, true) });
CAircraftEngineList e(
{ CAircraftEngine(1, true, 100), CAircraftEngine(2, false, 0), CAircraftEngine(3, true, 100) });
CAircraftParts p(l, true, 20, true, e, false);
p.setMSecsSinceEpoch(ts - deltaT * number); // values in past
return p;

View File

@@ -163,7 +163,8 @@ namespace MiscTest
CAircraftParts CTestInterpolatorParts::createTestParts(int number, qint64 ts, qint64 deltaT, bool onGround)
{
CAircraftLights l(true, false, true, false, true, false);
CAircraftEngineList e({ CAircraftEngine(1, true), CAircraftEngine(2, false), CAircraftEngine(3, true) });
CAircraftEngineList e(
{ CAircraftEngine(1, true, 100), CAircraftEngine(2, false, 0), CAircraftEngine(3, true, 100) });
CAircraftParts p(l, true, 20, true, e, false);
p.setMSecsSinceEpoch(ts - deltaT * number); // values in past
p.setTimeOffsetMs(0);