feat: Basic configuration for an ACARS protocol

This commit is contained in:
Thomas Zobler
2026-06-29 13:47:33 +02:00
parent 92da3a6658
commit 40c27ed415
25 changed files with 497 additions and 8 deletions

View File

@@ -115,6 +115,12 @@ namespace swift::core::context
return m_ownAircraft.getParts();
}
CAircraftAcars CContextOwnAircraft::getOwnAircraftAcars() const
{
QReadLocker l(&m_lockAircraft);
return m_ownAircraft.getAcars();
}
CAircraftModel CContextOwnAircraft::getOwnAircraftModel() const
{
QReadLocker l(&m_lockAircraft);
@@ -242,6 +248,15 @@ namespace swift::core::context
return true;
}
bool CContextOwnAircraft::updateOwnAcars(const CAircraftAcars &acars)
{
QWriteLocker l(&m_lockAircraft);
const bool changed = (m_ownAircraft.getAcars() != acars);
if (!changed) { return false; }
m_ownAircraft.setAcars(acars);
return true;
}
bool CContextOwnAircraft::updateOwnCG(const CLength &cg)
{
QWriteLocker l(&m_lockAircraft);

View File

@@ -17,6 +17,7 @@
#include "core/context/contextownaircraft.h"
#include "core/corefacadeconfig.h"
#include "core/swiftcoreexport.h"
#include "misc/aviation/aircraftacars.h"
#include "misc/aviation/aircraftparts.h"
#include "misc/aviation/aircraftsituationlist.h"
#include "misc/aviation/airlineicaocode.h"
@@ -88,6 +89,10 @@ namespace swift::core
//! \ingroup ownaircraftprovider
swift::misc::aviation::CAircraftParts getOwnAircraftParts() const override;
//! \copydoc swift::misc::simulation::IOwnAircraftProvider::getOwnAircraftAcars
//! \ingroup ownaircraftprovider
swift::misc::aviation::CAircraftAcars getOwnAircraftAcars() const override;
//! \copydoc swift::misc::simulation::IOwnAircraftProvider::getOwnAircraftModel
//! \ingroup ownaircraftprovider
swift::misc::simulation::CAircraftModel getOwnAircraftModel() const override;
@@ -110,6 +115,10 @@ namespace swift::core
//! \ingroup ownaircraftprovider
bool updateOwnParts(const swift::misc::aviation::CAircraftParts &parts) override;
//! \copydoc swift::misc::simulation::IOwnAircraftProvider::updateOwnAcars
//! \ingroup ownaircraftprovider
bool updateOwnAcars(const swift::misc::aviation::CAircraftAcars &acars) override;
//! \copydoc swift::misc::simulation::IOwnAircraftProvider::updateOwnParts
//! \ingroup ownaircraftprovider
bool updateOwnCG(const swift::misc::physical_quantities::CLength &cg) override;

View File

@@ -81,7 +81,8 @@ namespace swift::core::fsd
INF, /*!< Supervisor Privileged Information Request. */
FP, /*!< Send Cached Flight Plan. Response by SERVER. */
AircraftConfig, /*!< Aircraft Configuration */
EuroscopeSimData /*!< Broadcast to announce we request SIMDATA packets. */
EuroscopeSimData, /*!< Broadcast to announce we request SIMDATA packets. */
Acars /*!< Broadcast to announce we request ACARS packets. */
// There are many more which are only relevant to ATC clients.
};

View File

@@ -110,6 +110,9 @@ namespace swift::core::fsd
m_fsdSendMessageTimer.setObjectName(this->objectName().append(":m_fsdSendMessageTimer"));
connect(&m_fsdSendMessageTimer, &QTimer::timeout, this, [this]() { this->sendQueuedMessage(); });
m_fsdSendAcarsTimer.setObjectName(this->objectName().append(":m_fsdSendAcarsTimer"));
connect(&m_fsdSendAcarsTimer, &QTimer::timeout, this, [this]() { this->sendAcarsMessage(); });
fsdMessageSettingsChanged();
if (!m_statistics &&
@@ -818,6 +821,53 @@ namespace swift::core::fsd
}
}
void CFSDClient::sendAcarsMessage()
{
// TODO TZ
if (getServer().getEcosystem().isSystem(CEcosystem::VATSIM)) return;
if (this->getConnectionStatus().isDisconnected() && !m_unitTestMode) { return; }
if (m_loginMode == CLoginMode::Observer)
{
return; // observers don't send ACARS
}
else
{
if (this->isAcarsSendEnabled())
{
// TODO TZ
const CAircraftAcars currentAcars(this->getOwnAircraftAcars());
const QJsonObject previousAcars = m_sentAcars.toJson();
const QJsonObject currentAcarsJson = currentAcars.toJson();
const QJsonObject incrementalAcars = getIncrementalObject(previousAcars, currentAcarsJson);
m_sentAcarsCount++;
QString dataStr = "";
if (m_sentAcarsCount > 59)
{
dataStr = convertToUnicodeEscaped(
QJsonDocument(QJsonObject { { "full", currentAcarsJson } }).toJson(QJsonDocument::Compact));
m_sentAcarsCount = 0;
}
else
{
// If it hasn't changed, return
if (m_sentAcars == currentAcars) { return; }
dataStr = convertToUnicodeEscaped(QJsonDocument(QJsonObject { { "incremental", incrementalAcars } })
.toJson(QJsonDocument::Compact));
}
const QString receiver = "SERVER";
const ClientQuery clientQuery(getOwnCallsignAsString(), receiver, ClientQueryType::Acars, { dataStr });
sendQueuedMessage(clientQuery);
m_sentAcars = currentAcars;
}
}
}
void CFSDClient::sendFsdMessage(const QString &message)
{
// UNIT tests
@@ -1026,6 +1076,8 @@ namespace swift::core::fsd
void CFSDClient::sendIncrementalAircraftConfig()
{
// TODO TZ hier abschreiben
if (!m_unitTestMode && (!this->isConnected() || !this->getSetupForServer().sendAircraftParts())) { return; }
const CAircraftParts currentParts(this->getOwnAircraftParts());
@@ -1948,6 +2000,7 @@ namespace swift::core::fsd
m_atcStations.clear();
m_queuedFsdMessages.clear();
m_sentAircraftConfig = CAircraftParts::null();
m_sentAcars = CAircraftAcars::null();
m_loginSince = -1;
}
@@ -2000,6 +2053,12 @@ namespace swift::core::fsd
return (d & CFsdSetup::SendVisualPositions);
}
bool CFSDClient::isAcarsSendEnabled() const
{
const CFsdSetup::SendReceiveDetails d = this->getSetupForServer().getSendReceiveDetails();
return (d & CFsdSetup::SendAcars);
}
const CFsdSetup &CFSDClient::getSetupForServer() const { return m_server.getFsdSetup(); }
void CFSDClient::maybeHandleAtisReply(const CCallsign &sender, const CCallsign &receiver, const QString &message)
@@ -2336,6 +2395,7 @@ namespace swift::core::fsd
m_positionUpdateTimer.start(c_updatePositionIntervalMsec);
m_scheduledConfigUpdate.start(c_processingIntervalMsec);
m_fsdSendMessageTimer.start(c_sendFsdMsgIntervalMsec);
m_fsdSendAcarsTimer.start(c_sendAcarsIntervalMsec);
m_queuedFsdMessages.clear(); // clear everything before the timer is started
// interim positions

View File

@@ -10,6 +10,7 @@
#include "core/fsd/messagebase.h"
#include "core/swiftcoreexport.h"
#include "core/vatsim/vatsimsettings.h"
#include "misc/aviation/aircraftacars.h"
#include "misc/aviation/aircrafticaocode.h"
#include "misc/aviation/atcstationlist.h"
#include "misc/aviation/callsign.h"
@@ -365,6 +366,7 @@ namespace swift::core::fsd
//
void sendMessageString(const QString &message);
void sendQueuedMessage();
void sendAcarsMessage();
//! @}
//! @{
@@ -394,6 +396,14 @@ namespace swift::core::fsd
this->sendMessageString(messageToFSDString(message));
}
//! Acars Message send to FSD
template <class T>
void sendAcarsMessage(const T &message)
{
if (!message.isValid()) { return; }
this->sendMessageString(messageToFSDString(message));
}
//! @{
//! Unit test/debug functions
void sendFsdMessage(const QString &message);
@@ -517,6 +527,7 @@ namespace swift::core::fsd
bool isInterimPositionSendingEnabledForServer() const;
bool isInterimPositionReceivingEnabledForServer() const;
bool isVisualPositionSendingEnabledForServer() const;
bool isAcarsSendEnabled() const;
const swift::misc::network::CFsdSetup &getSetupForServer() const;
//! Handles ATIS replies from non-VATSIM servers. If the conditions are not met,
@@ -590,6 +601,9 @@ namespace swift::core::fsd
mutable QReadWriteLock m_lockConnectionStatus { QReadWriteLock::Recursive };
swift::misc::aviation::CAircraftParts m_sentAircraftConfig; //!< aircraft parts sent
swift::misc::aviation::CAircraftAcars m_sentAcars; //!< aircraft ACARS sent
int m_sentAcarsCount = 0; //!< how many ACARS messages sent
swift::misc::CTokenBucket m_tokenBucket; //!< used with aircraft parts messages
swift::misc::aviation::CCallsignSet m_interimPositionReceivers; //!< all aircraft receiving interim positions
swift::misc::network::CTextMessageList m_textMessagesToConsolidate; //!< waiting for new messages
@@ -633,6 +647,7 @@ namespace swift::core::fsd
QTimer m_interimPositionUpdateTimer { this }; //!< sending interim positions
QTimer m_visualPositionUpdateTimer { this }; //!< sending visual positions
QTimer m_fsdSendMessageTimer { this }; //!< FSD message sending
QTimer m_fsdSendAcarsTimer { this }; //!< ACARS message sending
qint64 m_additionalOffsetTime = 0; //!< additional offset time
@@ -696,6 +711,7 @@ namespace swift::core::fsd
static int constexpr c_updateVisualPositionIntervalMsec =
200; //!< interval for the VATSIM visual position updates (send our position and 6DOF velocity)
static int constexpr c_sendFsdMsgIntervalMsec = 10; //!< interval for FSD send messages
static int constexpr c_sendAcarsIntervalMsec = 1000; //!< interval for ACARS messages
bool m_stoppedSendingVisualPositions = false; //!< for when velocity drops to zero
bool m_serverWantsVisualPositions = false; //!< there are interested clients in range
unsigned m_visualPositionUpdateSentCount = 0; //!< for choosing when to send a periodic (slowfast) packet

View File

@@ -309,6 +309,7 @@ namespace swift::core::fsd
case ClientQueryType::INF: return "INF";
case ClientQueryType::FP: return "FP";
case ClientQueryType::AircraftConfig: return "ACC";
case ClientQueryType::Acars: return "ACARS";
case ClientQueryType::EuroscopeSimData: return "SIMDATA";
case ClientQueryType::Unknown: return "Unknown query type";
}

View File

@@ -35,7 +35,7 @@ namespace swift::gui::editors
ui->cb_GndFlagSend->isChecked(), ui->cb_GndFlagReceive->isChecked(),
ui->cb_FastPositionSend->isChecked(), ui->cb_FastPositionReceive->isChecked(),
ui->cb_VisualPositionSend->isChecked(), ui->cb_EuroscopeSimData->isChecked(),
ui->cb_IcaoEquipment->isChecked());
ui->cb_IcaoEquipment->isChecked(), ui->cb_FsdSendAcars->isChecked());
s.setForce3LetterAirlineCodes(ui->cb_3LetterAirlineICAO->isChecked());
return s;
}
@@ -58,6 +58,7 @@ namespace swift::gui::editors
ui->cb_3LetterAirlineICAO->setChecked(setup.force3LetterAirlineCodes());
ui->cb_EuroscopeSimData->setChecked(d & CFsdSetup::ReceiveEuroscopeSimData);
ui->cb_IcaoEquipment->setChecked(d & CFsdSetup::SendFplWithIcaoEquipment);
ui->cb_FsdSendAcars->setChecked(d & CFsdSetup::SendAcars);
}
void CFsdSetupForm::setAlwaysAllowOverride(bool allow)

View File

@@ -36,6 +36,15 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lbl_FsdSendAcars">
<property name="text">
<string>send ACARS:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="cb_AircraftPartsSend">
<property name="text">
@@ -57,6 +66,15 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="cb_FsdSendAcars">
<property name="text">
<string>send ACARS information over private networks</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="lbl_AircraftParts">
<property name="toolTip">

View File

@@ -17,6 +17,8 @@ add_library(misc SHARED
audio/registermetadataaudio.h
# Aviation
aviation/aircraftacars.cpp
aviation/aircraftacars.h
aviation/aircraftcategory.cpp
aviation/aircraftcategory.h
aviation/aircraftcategorylist.cpp
@@ -678,7 +680,7 @@ add_library(misc SHARED
weather/windlayer.h
weather/windlayerlist.cpp
weather/windlayerlist.h
)
)
if(APPLE)
target_sources(misc PRIVATE

View File

@@ -0,0 +1,152 @@
// SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#include "misc/aviation/aircraftacars.h"
#include <QtGlobal>
#include "QStringBuilder"
#include "misc/comparefunctions.h"
#include "misc/propertyindex.h"
#include "misc/stringutils.h"
SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAircraftAcars)
namespace swift::misc::aviation
{
CAircraftAcars::CAircraftAcars(int simRate, int fuelTotalquantity)
: m_simRate(simRate), m_fuelTotalquantity(fuelTotalquantity)
{}
// CAircraftAcars::CAircraftAcars(int simRate, qint64 timestamp) : m_simRate(simRate) {}
CAircraftAcars::CAircraftAcars(int simRate, int fuelTotalquantity, qint64 timestamp)
: m_simRate(simRate), m_fuelTotalquantity(fuelTotalquantity)
{
this->setMSecsSinceEpoch(timestamp);
}
QString CAircraftAcars::convertToQString(bool i18n) const
{
// return QStringLiteral("CAircraftAcars"); // Platzhalter, bitte anpassen!
return u"ts: " % this->getFormattedTimestampAndOffset(true) % u" details: " % this->getAcarsDetailsAsString() %
u" | simrate: " % QString::number(m_simRate);
}
QJsonObject CAircraftAcars::toIncrementalJson() const
{
QJsonObject json = this->toJson();
json.remove(attributeNameIsFullJson());
json.insert(attributeNameIsFullJson(), QJsonValue(false));
return json;
}
QJsonObject CAircraftAcars::toFullJson() const
{
QJsonObject json = this->toJson();
json.remove(attributeNameIsFullJson());
json.insert(attributeNameIsFullJson(), QJsonValue(true));
return json;
}
bool CAircraftAcars::isNull() const { return this->getAcarsDetails() == NotSet && m_simRate < 0; }
bool CAircraftAcars::equalValues(const CAircraftAcars &other) const
{
// currently same as some values are diabled for comparison
// but that could change in future
return other == *this;
}
const CAircraftAcars &CAircraftAcars::null()
{
static const CAircraftAcars null(1, 100);
return null;
}
const QString &CAircraftAcars::acarsDetailsToString(CAircraftAcars::AcarsDetails details)
{
static const QString guessed("guessed");
static const QString notset("not set");
static const QString fsd("FSD acars");
switch (details)
{
case GuessedAcars: return guessed;
case FSDAircraftAcars: return fsd;
case NotSet: break;
default: break;
}
return notset;
}
const QString &CAircraftAcars::attributeNameIsFullJson()
{
static const QString a("is_full_data");
return a;
}
QVariant CAircraftAcars::propertyByIndex(swift::misc::CPropertyIndexRef index) const
{
if (index.isMyself()) { return QVariant::fromValue(*this); }
if (ITimestampWithOffsetBased::canHandleIndex(index))
{
return ITimestampWithOffsetBased::propertyByIndex(index);
}
const auto i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexSimrate: return QVariant::fromValue(m_simRate);
case IndexFuelTotalQuantity: return QVariant::fromValue(m_fuelTotalquantity);
default: return CValueObject::propertyByIndex(index);
}
}
void CAircraftAcars::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
{
if (index.isMyself())
{
(*this) = variant.value<CAircraftAcars>();
return;
}
if (ITimestampWithOffsetBased::canHandleIndex(index))
{
ITimestampWithOffsetBased::setPropertyByIndex(index, variant);
return;
}
const auto i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexSimrate: m_simRate = variant.toInt(); break;
case IndexFuelTotalQuantity: m_fuelTotalquantity = variant.toInt(); break;
default: CValueObject::setPropertyByIndex(index, variant); break;
}
}
int CAircraftAcars::comparePropertyByIndex(CPropertyIndexRef index, const CAircraftAcars &compareValue) const
{
if (index.isMyself())
{
return ITimestampWithOffsetBased::comparePropertyByIndex(CPropertyIndex(), compareValue);
}
if (ITimestampWithOffsetBased::canHandleIndex(index))
{
return ITimestampWithOffsetBased::comparePropertyByIndex(index, compareValue);
}
const auto i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexSimrate: return Compare::compare(m_simRate, compareValue.getSimrate());
case IndexFuelTotalQuantity: return Compare::compare(m_fuelTotalquantity, compareValue.getFuelTotalquantity());
default: break;
}
Q_ASSERT_X(false, Q_FUNC_INFO, "No comparison");
return 0;
}
} // namespace swift::misc::aviation

View File

@@ -0,0 +1,136 @@
// SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
//! \file
#ifndef SWIFT_MISC_AVIATION_AIRCRAFTACARS_H
#define SWIFT_MISC_AVIATION_AIRCRAFTACARS_H
#include <QMetaType>
#include <QString>
// #include "misc/aviation/aircraftenginelist.h"
// #include "misc/aviation/aircraftlights.h"
#include "misc/metaclass.h"
#include "misc/propertyindexref.h"
#include "misc/swiftmiscexport.h"
#include "misc/timestampbased.h"
#include "misc/valueobject.h"
// SWIFT_DECLARE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAircraftAcars)
namespace swift::misc::aviation
{
//! Value object encapsulating information of aircraft's acars
class SWIFT_MISC_EXPORT CAircraftAcars : public CValueObject<CAircraftAcars>, public ITimestampWithOffsetBased
{
public:
//! Properties by index
enum ColumnIndex
{
IndexSimrate,
IndexFuelTotalQuantity
};
//! Acars Details
enum AcarsDetails
{
NotSet,
FSDAircraftAcars,
GuessedAcars
};
//! Default constructor
CAircraftAcars() = default;
//! Default constructor
CAircraftAcars(int simRate, int fuelTotalquantity);
//! Constructor
CAircraftAcars(int simRate, int fuelTotalquantity, qint64 timestamp);
//! \copydoc swift::misc::mixin::Index::propertyByIndex
QVariant propertyByIndex(CPropertyIndexRef index) const;
//! \copydoc swift::misc::mixin::Index::setPropertyByIndex
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant);
//! \copydoc swift::misc::mixin::Index::comparePropertyByIndex
int comparePropertyByIndex(CPropertyIndexRef index, const CAircraftAcars &compareValue) const;
//! Get simrate
int getSimrate() const { return m_simRate; }
//! Set simrate
// void setSimrate(int simRate) { m_simRate = simRate; }
//! Get fuel total quantity
double getFuelTotalquantity() const { return m_fuelTotalquantity; }
//! Set fuel total quantity
void setFuelTotalquantity(double fuelTotalquantity) { m_fuelTotalquantity = fuelTotalquantity; }
//! Get acars details
AcarsDetails getAcarsDetails() const { return static_cast<AcarsDetails>(m_acarsDetails); }
//! Acars details as string
const QString &getAcarsDetailsAsString() const { return acarsDetailsToString(this->getAcarsDetails()); }
//! Set acars details
void setAcarsDetails(AcarsDetails details) { m_acarsDetails = static_cast<int>(details); }
//! \copydoc swift::misc::mixin::String::toQString
QString convertToQString(bool i18n = false) const;
//! Incremental JSON object
//! \remark same as toJson, but sets \c is_full_data to \c false
QJsonObject toIncrementalJson() const;
//! Full JSON Object
//! \remark same as toJson, but sets \c is_full_data to \c true
QJsonObject toFullJson() const;
//! NULL acars object?
bool isNull() const;
//! Equal values, but not comparing timestamp etc.
bool equalValues(const CAircraftAcars &other) const;
//! NULL acars object
static const CAircraftAcars &null();
//! Convert to QString
static const QString &acarsDetailsToString(AcarsDetails details);
//! Attribute name
static const QString &attributeNameIsFullJson();
//! Number of attributes for full JSON
static constexpr int attributesCountFullJson = 2;
private:
// Fuel availability : Reports on the remaining fuel quantity
// Error messages : Reports on potential problems or
// malfunctions in the aircraft.Engine condition
// slid
// simulation rate : Reports on the current simulation rate of the aircraft
int m_acarsDetails = static_cast<int>(NotSet);
int m_simRate = 1;
double m_fuelTotalquantity = -1;
// QString m_guessingDetails; //!< just for debugging, not via DBus ...
SWIFT_METACLASS(
CAircraftAcars,
SWIFT_METAMEMBER_NAMED(simRate, "simrate"),
SWIFT_METAMEMBER_NAMED(fuelTotalquantity, "fueltotalquantity"),
SWIFT_METAMEMBER(acarsDetails, 0, DisabledForJson | DisabledForComparison),
SWIFT_METAMEMBER(timestampMSecsSinceEpoch, 0, DisabledForJson | DisabledForComparison),
SWIFT_METAMEMBER(timeOffsetMs, 0, DisabledForJson | DisabledForComparison));
};
} // namespace swift::misc::aviation
Q_DECLARE_METATYPE(swift::misc::aviation::CAircraftAcars)
#endif // SWIFT_MISC_AVIATION_AIRCRAFTACARS_H

View File

@@ -13,12 +13,12 @@ namespace swift::misc::aviation
{
CAircraftEngine::CAircraftEngine(int number, bool on) : m_number(number), m_on(on)
{
Q_ASSERT_X(number > 0, "CAircraftEngine", "Engine numbers have to be >= 1");
Q_ASSERT_X(number > 0, "CAircraftEngine", "Engine numbers have to be > 1");
}
void CAircraftEngine::setNumber(int number)
{
Q_ASSERT_X(number > 0, "setNumber", "Engine numbers have to be >= 1");
Q_ASSERT_X(number > 0, "setNumber", "Engine numbers have to be > 1");
m_number = number;
}

View File

@@ -51,7 +51,7 @@ namespace swift::misc::network
void CFsdSetup::setSendReceiveDetails(bool partsSend, bool partsReceive, bool gndSend, bool gndReceive,
bool interimSend, bool interimReceive, bool visualSend,
bool euroscopeSimDataReceive, bool icaoEquipment)
bool euroscopeSimDataReceive, bool icaoEquipment, bool sendAcars)
{
SendReceiveDetails s = Nothing;
if (partsSend) { s |= SendAircraftParts; }
@@ -63,6 +63,7 @@ namespace swift::misc::network
if (visualSend) { s |= SendVisualPositions; }
if (euroscopeSimDataReceive) { s |= ReceiveEuroscopeSimData; }
if (icaoEquipment) { s |= SendFplWithIcaoEquipment; }
if (sendAcars) { s |= SendAcars; }
this->setSendReceiveDetails(s);
}

View File

@@ -44,6 +44,7 @@ namespace swift::misc::network
SendVisualPositions = 1 << 7, //!< visual positions out
ReceiveEuroscopeSimData = 1 << 8, //!< euroscope SIMDATA in
SendFplWithIcaoEquipment = 1 << 9, //!< send flightplan with ICAO equipment code instead of FAA code
SendAcars = 1 << 10, //!< send ACARS information over private networks
AllSending = SendAircraftParts | SendInterimPositions | SendVisualPositions | SendGndFlag, //!< all out
AllReceive = ReceiveAircraftParts | ReceiveInterimPositions | ReceiveGndFlag, //!< all in
All = AllReceive | AllSending, //!< all
@@ -94,7 +95,7 @@ namespace swift::misc::network
//! Set send / receive details
void setSendReceiveDetails(bool partsSend, bool partsReceive, bool gndSend, bool gndReceive, bool interimSend,
bool interimReceive, bool visualSend, bool euroscopeSimDataReceive,
bool icaoEquipment);
bool icaoEquipmentm, bool sendAcars);
//! @{
//! FSD setup flags

View File

@@ -52,6 +52,7 @@ namespace swift::misc
GlobalIndexCComSystem = 3100,
GlobalIndexCModulator = 3200,
GlobalIndexCTransponder = 3300,
GlobalIndexCAircraftAcars = 3400,
GlobalIndexCAircraftCategory = 3500,
GlobalIndexCAircraftIcaoCode = 3600,
GlobalIndexCAirlineIcaoCode = 3700,

View File

@@ -62,6 +62,12 @@ namespace swift::misc::simulation
return this->provider()->getOwnAircraftParts();
}
CAircraftAcars COwnAircraftAware::getOwnAircraftAcars() const
{
Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
return this->provider()->getOwnAircraftAcars();
}
CAircraftModel COwnAircraftAware::getOwnAircraftModel() const
{
Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
@@ -118,6 +124,12 @@ namespace swift::misc::simulation
return this->provider()->updateOwnParts(parts);
}
bool COwnAircraftAware::updateOwnAcars(const CAircraftAcars &acars)
{
Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
return this->provider()->updateOwnAcars(acars);
}
bool COwnAircraftAware::updateOwnCG(const CLength &cg)
{
Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");

View File

@@ -9,6 +9,7 @@
#include <QObject>
#include <QtGlobal>
#include "misc/aviation/aircraftacars.h"
#include "misc/aviation/aircraftparts.h"
#include "misc/aviation/airlineicaocode.h"
#include "misc/aviation/callsign.h"
@@ -65,6 +66,10 @@ namespace swift::misc
//! \threadsafe
virtual aviation::CAircraftParts getOwnAircraftParts() const = 0;
//! Own aircraft's parts
//! \threadsafe
virtual aviation::CAircraftAcars getOwnAircraftAcars() const = 0;
//! Own aircraft model
//! \threadsafe
virtual swift::misc::simulation::CAircraftModel getOwnAircraftModel() const = 0;
@@ -93,6 +98,9 @@ namespace swift::misc
//! Update own parts
virtual bool updateOwnParts(const aviation::CAircraftParts &parts) = 0;
//! Update own acars
virtual bool updateOwnAcars(const aviation::CAircraftAcars &acars) = 0;
//! Update own aircraft's CG (aka vertical offset)
virtual bool updateOwnCG(const physical_quantities::CLength &cg) = 0;
@@ -153,6 +161,9 @@ namespace swift::misc
//! \copydoc IOwnAircraftProvider::getOwnAircraftParts
aviation::CAircraftParts getOwnAircraftParts() const;
//! \copydoc IOwnAircraftProvider::getOwnAircraftAcars
aviation::CAircraftAcars getOwnAircraftAcars() const;
//! \copydoc IOwnAircraftProvider::getOwnAircraftModel
swift::misc::simulation::CAircraftModel getOwnAircraftModel() const;
@@ -196,6 +207,9 @@ namespace swift::misc
//! \copydoc IOwnAircraftProvider::updateOwnParts
bool updateOwnParts(const aviation::CAircraftParts &parts);
//! \copydoc IOwnAircraftProvider::updateOwnAcars
bool updateOwnAcars(const aviation::CAircraftAcars &acars);
//! \copydoc IOwnAircraftProvider::updateOwnCG
bool updateOwnCG(const physical_quantities::CLength &cg);

View File

@@ -52,6 +52,13 @@ namespace swift::misc::simulation
return m_ownAircraft.getParts();
}
CAircraftAcars COwnAircraftProviderDummy::getOwnAircraftAcars() const
{
// TODO TZ: implement this properly, for now just return parts as a placeholder
QReadLocker l(&m_lock);
return m_ownAircraft.getAcars();
}
CAircraftModel COwnAircraftProviderDummy::getOwnAircraftModel() const
{
QReadLocker l(&m_lock);
@@ -117,6 +124,13 @@ namespace swift::misc::simulation
return true;
}
bool COwnAircraftProviderDummy::updateOwnAcars(const CAircraftAcars &acars)
{
QWriteLocker l(&m_lock);
m_ownAircraft.setAcars(acars);
return true;
}
bool COwnAircraftProviderDummy::updateOwnCG(const CLength &cg)
{
QWriteLocker l(&m_lock);

View File

@@ -9,6 +9,7 @@
#include <QObject>
#include <QReadWriteLock>
#include "misc/aviation/aircraftacars.h"
#include "misc/aviation/aircraftparts.h"
#include "misc/aviation/airlineicaocode.h"
#include "misc/aviation/comsystem.h"
@@ -67,6 +68,9 @@ namespace swift::misc
//! \copydoc IOwnAircraftProvider::getOwnAircraftParts
swift::misc::aviation::CAircraftParts getOwnAircraftParts() const override;
//! \copydoc IOwnAircraftProvider::getOwnAircraftAcars
swift::misc::aviation::CAircraftAcars getOwnAircraftAcars() const override;
//! \copydoc IOwnAircraftProvider::getOwnAircraftModel
swift::misc::simulation::CAircraftModel getOwnAircraftModel() const override;
@@ -106,6 +110,9 @@ namespace swift::misc
//! \copydoc IOwnAircraftProvider::updateOwnParts
bool updateOwnParts(const swift::misc::aviation::CAircraftParts &parts) override;
//! \copydoc IOwnAircraftProvider::updateOwnAcars
bool updateOwnAcars(const swift::misc::aviation::CAircraftAcars &acars) override;
//! \copydoc IOwnAircraftProvider::updateOwnCG
bool updateOwnCG(const swift::misc::physical_quantities::CLength &cg) override;

View File

@@ -280,6 +280,8 @@ namespace swift::misc::simulation
void CSimulatedAircraft::setParts(const CAircraftParts &parts) { m_parts = parts; }
void CSimulatedAircraft::setAcars(const CAircraftAcars &acars) { m_acars = acars; }
void CSimulatedAircraft::setLights(CAircraftLights &lights) { m_parts.setLights(lights); }
void CSimulatedAircraft::setAllLightsOn() { m_parts.setAllLightsOn(); }

View File

@@ -13,6 +13,7 @@
#include <QVector3D>
#include <QtGlobal>
#include "misc/aviation/aircraftacars.h"
#include "misc/aviation/aircraftlights.h"
#include "misc/aviation/aircraftparts.h"
#include "misc/aviation/aircraftsituation.h"
@@ -349,6 +350,9 @@ namespace swift::misc
//! Get aircraft parts
const aviation::CAircraftParts &getParts() const { return m_parts; }
//! Get aircraft acars
const aviation::CAircraftAcars &getAcars() const { return m_acars; }
//! Number of engines
int getEnginesCount() const;
@@ -358,6 +362,9 @@ namespace swift::misc
//! Set aircraft parts
void setParts(const aviation::CAircraftParts &parts);
//! Set aircraft acars
void setAcars(const aviation::CAircraftAcars &acars);
//! Set aircraft lights
void setLights(aviation::CAircraftLights &lights);
@@ -493,6 +500,7 @@ namespace swift::misc
aviation::CComSystem m_com2system;
aviation::CTransponder m_transponder;
aviation::CAircraftParts m_parts;
aviation::CAircraftAcars m_acars;
aviation::CSelcal m_selcal;
CAircraftModelList m_models = {
{ CAircraftModel(), CAircraftModel() }
@@ -515,6 +523,7 @@ namespace swift::misc
SWIFT_METAMEMBER(com2system),
SWIFT_METAMEMBER(transponder),
SWIFT_METAMEMBER(parts),
SWIFT_METAMEMBER(acars),
SWIFT_METAMEMBER(selcal),
SWIFT_METAMEMBER(models),
SWIFT_METAMEMBER(enabled),

View File

@@ -10,6 +10,7 @@
#include "../fscommon/simulatorfscommonfunctions.h"
#include "simconnectsymbols.h"
#include "misc/aviation/aircraftacars.h"
#include "misc/aviation/aircraftenginelist.h"
#include "misc/aviation/aircraftparts.h"
#include "misc/logmessage.h"
@@ -185,6 +186,13 @@ namespace swift::simplugin::fsxcommon
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "TITLE",
nullptr, SIMCONNECT_DATATYPE_STRING256);
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
"FUEL TOTAL QUANTITY", "Gallons");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "SIMULATION RATE",
"Number");
if (isFailure(hr))
{
CLogMessage(static_cast<CSimConnectDefinitions *>(nullptr)).error(u"SimConnect error: initOwnAircraft %1")

View File

@@ -79,6 +79,10 @@ namespace swift::simplugin::fsxcommon
// 44
double altitudeCalibratedFt; //!< Altitude without temperature effect (ft, FS2020)
// 45
double fuelTotalCapacity; //!< Altitude without temperature effect (ft, FS2020)
// 46
double simulationRate; //!< Simulation rate (FS2020)
// 47
};
//! Data struct of aircraft position

View File

@@ -754,9 +754,14 @@ namespace swift::simplugin::fsxcommon
dtb(simulatorOwnAircraft.spoilersHandlePosition), engines,
dtb(simulatorOwnAircraft.simOnGround), ts);
// TODO TZ s
const CAircraftAcars acars(qRound(simulatorOwnAircraft.simulationRate),
qRound(simulatorOwnAircraft.fuelTotalCapacity * 100), ts);
// set values
this->updateOwnSituationAndGroundElevation(aircraftSituation);
this->updateOwnParts(parts);
this->updateOwnAcars(acars);
// When I change cockpit values in the sim (from GUI to simulator, not originating from simulator)
// it takes a little while before these values are set in the simulator.

View File

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