diff --git a/src/core/context/contextownaircraftimpl.cpp b/src/core/context/contextownaircraftimpl.cpp index 68bb2b7d1..46a7e2893 100644 --- a/src/core/context/contextownaircraftimpl.cpp +++ b/src/core/context/contextownaircraftimpl.cpp @@ -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); diff --git a/src/core/context/contextownaircraftimpl.h b/src/core/context/contextownaircraftimpl.h index bb760560f..aa33b05c3 100644 --- a/src/core/context/contextownaircraftimpl.h +++ b/src/core/context/contextownaircraftimpl.h @@ -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; diff --git a/src/core/fsd/enums.h b/src/core/fsd/enums.h index 86e0c747f..fedff47d5 100644 --- a/src/core/fsd/enums.h +++ b/src/core/fsd/enums.h @@ -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. }; diff --git a/src/core/fsd/fsdclient.cpp b/src/core/fsd/fsdclient.cpp index 070d30c36..5cf8fd96d 100644 --- a/src/core/fsd/fsdclient.cpp +++ b/src/core/fsd/fsdclient.cpp @@ -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 diff --git a/src/core/fsd/fsdclient.h b/src/core/fsd/fsdclient.h index 01308812b..7ed0669a4 100644 --- a/src/core/fsd/fsdclient.h +++ b/src/core/fsd/fsdclient.h @@ -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 + 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 diff --git a/src/core/fsd/serializer.cpp b/src/core/fsd/serializer.cpp index d8dfd39b3..81c080b3d 100644 --- a/src/core/fsd/serializer.cpp +++ b/src/core/fsd/serializer.cpp @@ -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"; } diff --git a/src/gui/editors/fsdsetupform.cpp b/src/gui/editors/fsdsetupform.cpp index ff08f7b3c..5f7a57989 100644 --- a/src/gui/editors/fsdsetupform.cpp +++ b/src/gui/editors/fsdsetupform.cpp @@ -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) diff --git a/src/gui/editors/fsdsetupform.ui b/src/gui/editors/fsdsetupform.ui index 160de85df..ffa273396 100644 --- a/src/gui/editors/fsdsetupform.ui +++ b/src/gui/editors/fsdsetupform.ui @@ -36,6 +36,15 @@ + + + + + send ACARS: + + + + @@ -57,6 +66,15 @@ + + + + + send ACARS information over private networks + + + + diff --git a/src/misc/CMakeLists.txt b/src/misc/CMakeLists.txt index ab958d104..f5e5b23b1 100644 --- a/src/misc/CMakeLists.txt +++ b/src/misc/CMakeLists.txt @@ -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 diff --git a/src/misc/aviation/aircraftacars.cpp b/src/misc/aviation/aircraftacars.cpp new file mode 100644 index 000000000..7acd10039 --- /dev/null +++ b/src/misc/aviation/aircraftacars.cpp @@ -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 + +#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(); + 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(); + return; + } + if (ITimestampWithOffsetBased::canHandleIndex(index)) + { + ITimestampWithOffsetBased::setPropertyByIndex(index, variant); + return; + } + + const auto i = index.frontCasted(); + 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(); + 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 diff --git a/src/misc/aviation/aircraftacars.h b/src/misc/aviation/aircraftacars.h new file mode 100644 index 000000000..d3607c0bd --- /dev/null +++ b/src/misc/aviation/aircraftacars.h @@ -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 +#include + +// #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, 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(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(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(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 \ No newline at end of file diff --git a/src/misc/aviation/aircraftengine.cpp b/src/misc/aviation/aircraftengine.cpp index ae83707fe..c5828a7bc 100644 --- a/src/misc/aviation/aircraftengine.cpp +++ b/src/misc/aviation/aircraftengine.cpp @@ -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; } diff --git a/src/misc/network/fsdsetup.cpp b/src/misc/network/fsdsetup.cpp index 9af66a459..8102b0405 100644 --- a/src/misc/network/fsdsetup.cpp +++ b/src/misc/network/fsdsetup.cpp @@ -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); } diff --git a/src/misc/network/fsdsetup.h b/src/misc/network/fsdsetup.h index 901945353..2831a7823 100644 --- a/src/misc/network/fsdsetup.h +++ b/src/misc/network/fsdsetup.h @@ -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 diff --git a/src/misc/propertyindexref.h b/src/misc/propertyindexref.h index 3d442963c..f38055ab6 100644 --- a/src/misc/propertyindexref.h +++ b/src/misc/propertyindexref.h @@ -52,6 +52,7 @@ namespace swift::misc GlobalIndexCComSystem = 3100, GlobalIndexCModulator = 3200, GlobalIndexCTransponder = 3300, + GlobalIndexCAircraftAcars = 3400, GlobalIndexCAircraftCategory = 3500, GlobalIndexCAircraftIcaoCode = 3600, GlobalIndexCAirlineIcaoCode = 3700, diff --git a/src/misc/simulation/ownaircraftprovider.cpp b/src/misc/simulation/ownaircraftprovider.cpp index 1e50cb21d..cee30abe7 100644 --- a/src/misc/simulation/ownaircraftprovider.cpp +++ b/src/misc/simulation/ownaircraftprovider.cpp @@ -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"); diff --git a/src/misc/simulation/ownaircraftprovider.h b/src/misc/simulation/ownaircraftprovider.h index bb476bcd1..f59eb25b7 100644 --- a/src/misc/simulation/ownaircraftprovider.h +++ b/src/misc/simulation/ownaircraftprovider.h @@ -9,6 +9,7 @@ #include #include +#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); diff --git a/src/misc/simulation/ownaircraftproviderdummy.cpp b/src/misc/simulation/ownaircraftproviderdummy.cpp index b2f397b6b..fb2ea1d93 100644 --- a/src/misc/simulation/ownaircraftproviderdummy.cpp +++ b/src/misc/simulation/ownaircraftproviderdummy.cpp @@ -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); diff --git a/src/misc/simulation/ownaircraftproviderdummy.h b/src/misc/simulation/ownaircraftproviderdummy.h index e95ef629f..8d695eb9d 100644 --- a/src/misc/simulation/ownaircraftproviderdummy.h +++ b/src/misc/simulation/ownaircraftproviderdummy.h @@ -9,6 +9,7 @@ #include #include +#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; diff --git a/src/misc/simulation/simulatedaircraft.cpp b/src/misc/simulation/simulatedaircraft.cpp index 4806ac86b..8cec00fb1 100644 --- a/src/misc/simulation/simulatedaircraft.cpp +++ b/src/misc/simulation/simulatedaircraft.cpp @@ -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(); } diff --git a/src/misc/simulation/simulatedaircraft.h b/src/misc/simulation/simulatedaircraft.h index 0ecf5ba99..3a11ed1fc 100644 --- a/src/misc/simulation/simulatedaircraft.h +++ b/src/misc/simulation/simulatedaircraft.h @@ -13,6 +13,7 @@ #include #include +#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), diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp index 1ee57e99f..9061a6c16 100644 --- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp +++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp @@ -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(nullptr)).error(u"SimConnect error: initOwnAircraft %1") diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h index d23a3497c..6eaec032b 100644 --- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h +++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h @@ -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 diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp index e130562a6..a472c48c1 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp +++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp @@ -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. diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp index 68643c4aa..67d2b8de0 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp +++ b/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp @@ -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(&pObjData->dwData);