From 93a18f433c2c1fe611da75381da191013b2e2cd6 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 21 Dec 2016 22:43:45 +0100 Subject: [PATCH] refs #840, FSX driver: get ground elevation from simulator * fixed wrong request id * made functions private where possible * added data definitions for simobject data --- .../fsx/simconnectdatadefinition.cpp | 31 ++- .../simulator/fsx/simconnectdatadefinition.h | 24 ++- .../simulator/fsx/simconnectobject.cpp | 9 + src/plugins/simulator/fsx/simconnectobject.h | 15 +- src/plugins/simulator/fsx/simulatorfsx.cpp | 181 +++++++++++------- src/plugins/simulator/fsx/simulatorfsx.h | 66 ++++--- .../fsx/simulatorfsxsimconnectproc.cpp | 53 +++-- 7 files changed, 253 insertions(+), 126 deletions(-) diff --git a/src/plugins/simulator/fsx/simconnectdatadefinition.cpp b/src/plugins/simulator/fsx/simconnectdatadefinition.cpp index 309e78d63..a0b935347 100644 --- a/src/plugins/simulator/fsx/simconnectdatadefinition.cpp +++ b/src/plugins/simulator/fsx/simconnectdatadefinition.cpp @@ -16,7 +16,6 @@ namespace BlackSimPlugin { namespace Fsx { - CSimConnectDefinitions::CSimConnectDefinitions() { } HRESULT CSimConnectDefinitions::initDataDefinitionsWhenConnected(const HANDLE hSimConnect) @@ -24,6 +23,7 @@ namespace BlackSimPlugin HRESULT hr = S_OK; hr += initOwnAircraft(hSimConnect); hr += initRemoteAircraft(hSimConnect); + hr += initRemoteAircraftSimData(hSimConnect); hr += initSimulatorEnvironment(hSimConnect); hr += initSbDataArea(hSimConnect); return hr; @@ -32,14 +32,14 @@ namespace BlackSimPlugin HRESULT CSimConnectDefinitions::initOwnAircraft(const HANDLE hSimConnect) { HRESULT hr = S_OK; - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "Plane Latitude", "Degrees"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "Plane Longitude", "Degrees"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "Plane Altitude", "Feet"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "Plane Heading Degrees True", "Degrees"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "Plane Pitch Degrees", "Degrees"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "Plane Bank Degrees", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE LATITUDE", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE LONGITUDE", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE ALTITUDE", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE HEADING DEGREES TRUE", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE PITCH DEGREES", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE BANK DEGREES", "Degrees"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "GROUND VELOCITY", "Knots"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "GROUND ALTITUDE", "Meters"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "GROUND ALTITUDE", "Feet"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "SIM ON GROUND", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT STROBE", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT LANDING", "Bool"); @@ -106,7 +106,21 @@ namespace BlackSimPlugin { CLogMessage(static_cast(nullptr)).error("SimConnect error: initRemoteAircraftSituation %1") << hr; } + return hr; + } + HRESULT CSimConnectDefinitions::initRemoteAircraftSimData(const HANDLE hSimConnect) + { + HRESULT hr = S_OK; + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "PLANE LATITUDE", "degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "PLANE LONGITUDE", "degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "PLANE ALTITUDE", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "GROUND ALTITUDE", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "STATIC CG TO GROUND", "Feet"); + if (hr != S_OK) + { + CLogMessage(static_cast(nullptr)).error("SimConnect error: initRemoteAircraftSimData %1") << hr; + } return hr; } @@ -162,6 +176,5 @@ namespace BlackSimPlugin } return hr; } - } // namespace } // namespace diff --git a/src/plugins/simulator/fsx/simconnectdatadefinition.h b/src/plugins/simulator/fsx/simconnectdatadefinition.h index 2457c3b7d..aca141d61 100644 --- a/src/plugins/simulator/fsx/simconnectdatadefinition.h +++ b/src/plugins/simulator/fsx/simconnectdatadefinition.h @@ -38,7 +38,7 @@ namespace BlackSimPlugin double pitch; //!< Pitch (deg) double bank; //!< Bank (deg) double velocity; //!< Ground velocity - double elevation; //!< Elevation (m) + double elevation; //!< Elevation (ft) double simOnGround; //!< Is aircraft on ground? double lightStrobe; //!< Is strobe light on? @@ -92,6 +92,19 @@ namespace BlackSimPlugin double engine4Combustion; //!< Engine 4 combustion flag }; + //! Data for AI object sent back from simulator + struct DataDefinitionRemoteAircraftSimData + { + double latitude; //!< Latitude (deg) + double longitude; //!< Longitude (deg) + double altitude; //!< Altitude (ft) + double elevation; //!< Elevation (ft) + double cgToGround; //!< CG to ground (ft) + + //! Above ground ft + double aboveGround() const { return altitude - elevation; } + }; + //! Data struct simulator environment struct DataDefinitionSimEnvironment { @@ -142,6 +155,7 @@ namespace BlackSimPlugin DataOwnAircraftTitle, DataRemoteAircraftParts, DataRemoteAircraftPosition, + DataRemoteAircraftSimData, DataSimEnvironment, DataClientAreaSb, //!< whole SB area DataClientAreaSbIdent, //!< ident single value @@ -155,7 +169,8 @@ namespace BlackSimPlugin RequestRemoveAircraft, RequestOwnAircraftTitle, RequestSimEnvironment, - RequestSbData, //!< SB client area / XPDR mode + RequestSbData, //!< SB client area / XPDR mode + RequestEndMarker //!< free request ids can start here }; //! Constructor @@ -171,9 +186,12 @@ namespace BlackSimPlugin //! Initialize data definition for our own aircraft static HRESULT initOwnAircraft(const HANDLE hSimConnect); - //! Initialize data definition for remote aircrafts + //! Initialize data definition for remote aircraft static HRESULT initRemoteAircraft(const HANDLE hSimConnect); + //! Initialize data for remote aircraft queried from simulator + static HRESULT initRemoteAircraftSimData(const HANDLE hSimConnect); + //! Initialize data definition for Simulator environment static HRESULT initSimulatorEnvironment(const HANDLE hSimConnect); diff --git a/src/plugins/simulator/fsx/simconnectobject.cpp b/src/plugins/simulator/fsx/simconnectobject.cpp index 0f959116c..565f5ef92 100644 --- a/src/plugins/simulator/fsx/simconnectobject.cpp +++ b/src/plugins/simulator/fsx/simconnectobject.cpp @@ -75,6 +75,15 @@ namespace BlackSimPlugin return CSimConnectObject(); } + CSimConnectObject CSimConnectObjects::getSimObjectForRequestId(DWORD requestId) const + { + for (const CSimConnectObject &simObject : this->values()) + { + if (simObject.getRequestId() == requestId) { return simObject; } + } + return CSimConnectObject(); + } + bool CSimConnectObjects::isKnownSimObjectId(DWORD objectId) const { const CSimConnectObject simObject(getSimObjectForObjectId(objectId)); diff --git a/src/plugins/simulator/fsx/simconnectobject.h b/src/plugins/simulator/fsx/simconnectobject.h index 0b6123d32..f66affc33 100644 --- a/src/plugins/simulator/fsx/simconnectobject.h +++ b/src/plugins/simulator/fsx/simconnectobject.h @@ -16,8 +16,7 @@ #include "simconnect/SimConnect.h" #include -namespace BlackMisc { class IInterpolator; } - +namespace BlackMisc { namespace Simulation { class IInterpolator; } } namespace BlackSimPlugin { namespace Fsx @@ -44,6 +43,12 @@ namespace BlackSimPlugin //! Simulated aircraft model string const QString &getAircraftModelString() const { return m_aircraft.getModelString(); } + //! How often do we request data from simulator for this remote aircraft + SIMCONNECT_PERIOD getSimDataPeriod() const { return m_requestSimDataPeriod; } + + //! How often do we request data from simulator for this remote aircraft + void setSimDataPeriod(SIMCONNECT_PERIOD period) { m_requestSimDataPeriod = period; } + //! Set Simconnect request id void setRequestId(DWORD id) { m_requestId = id; m_validRequestId = true; } @@ -87,6 +92,7 @@ namespace BlackSimPlugin BlackMisc::Simulation::CSimulatedAircraft m_aircraft; DWORD m_requestId = 0; DWORD m_objectId = 0; + SIMCONNECT_PERIOD m_requestSimDataPeriod = SIMCONNECT_PERIOD_NEVER; //!< how often do we query ground elevation bool m_validRequestId = false; bool m_validObjectId = false; bool m_confirmedAdded = false; @@ -103,9 +109,12 @@ namespace BlackSimPlugin //! Find which callsign belongs to the object id BlackMisc::Aviation::CCallsign getCallsignForObjectId(DWORD objectId) const; - //! Find which callsign belongs to the object id + //! Get object per object id CSimConnectObject getSimObjectForObjectId(DWORD objectId) const; + //! Get object per request id + CSimConnectObject getSimObjectForRequestId(DWORD requestId) const; + //! Is the object id one of our AI objects? bool isKnownSimObjectId(DWORD objectId) const; diff --git a/src/plugins/simulator/fsx/simulatorfsx.cpp b/src/plugins/simulator/fsx/simulatorfsx.cpp index 37650523b..37f8a86c3 100644 --- a/src/plugins/simulator/fsx/simulatorfsx.cpp +++ b/src/plugins/simulator/fsx/simulatorfsx.cpp @@ -9,13 +9,15 @@ #include "simulatorfsx.h" #include "blackcore/application.h" -#include "blackmisc/interpolatorlinear.h" #include "blackmisc/network/textmessage.h" #include "blackmisc/simulation/fscommon/bcdconversions.h" #include "blackmisc/simulation/fsx/simconnectutilities.h" -#include "blackmisc/simulation/simulatorplugininfo.h" #include "blackmisc/simulation/aircraftmodel.h" +#include "blackmisc/simulation/interpolatorlinear.h" +#include "blackmisc/simulation/interpolationhints.h" +#include "blackmisc/simulation/simulatorplugininfo.h" #include "blackmisc/aviation/airportlist.h" +#include "blackmisc/geo/elevationplane.h" #include "blackmisc/logmessage.h" #include "blackmisc/threadutils.h" #include "blackmisc/verify.h" @@ -49,11 +51,11 @@ namespace BlackSimPlugin Q_ASSERT_X(ownAircraftProvider, Q_FUNC_INFO, "Missing provider"); Q_ASSERT_X(remoteAircraftProvider, Q_FUNC_INFO, "Missing provider"); Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing global object"); - this->m_realityBubbleTimer.setInterval(20 * 1000); + m_realityBubbleTimer.setInterval(20 * 1000); connect(&m_realityBubbleTimer, &QTimer::timeout, this, &CSimulatorFsx::ps_addAircraftCurrentlyOutOfBubble); m_useFsuipc = true; // Temporarily enabled until Simconnect Weather is implemented. - this->m_interpolator = new CInterpolatorLinear(remoteAircraftProvider, this); + m_interpolator = new CInterpolatorLinear(remoteAircraftProvider, this); m_defaultModel = { "Boeing 737-800 Paint1", @@ -155,8 +157,8 @@ namespace BlackSimPlugin // initial position if interpolator has data, otherwise do nothing setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available - const DWORD requestId = m_requestId++; - SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation()); + const DWORD requestId = obtainRequestId(); + SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation(), CInterpolationHints()); const QString modelString(addedAircraft.getModelString()); if (m_interpolationRenderingSetup.showSimulatorDebugMessages()) @@ -195,9 +197,9 @@ namespace BlackSimPlugin if (!this->isSimulating()) { return false; } // actually those data should be the same as ownAircraft - CComSystem newCom1 = ownAircraft.getCom1System(); - CComSystem newCom2 = ownAircraft.getCom2System(); - CTransponder newTransponder = ownAircraft.getTransponder(); + const CComSystem newCom1 = ownAircraft.getCom1System(); + const CComSystem newCom2 = ownAircraft.getCom2System(); + const CTransponder newTransponder = ownAircraft.getTransponder(); bool changed = false; if (newCom1.getFrequencyActive() != this->m_simCom1.getFrequencyActive()) @@ -356,7 +358,7 @@ namespace BlackSimPlugin void CSimulatorFsx::onSimStopped() { - int oldStatus = getSimulatorStatus(); + const int oldStatus = getSimulatorStatus(); m_simSimulating = false; emitSimulatorCombinedStatus(oldStatus); } @@ -372,6 +374,18 @@ namespace BlackSimPlugin disconnectFrom(); } + DWORD CSimulatorFsx::obtainRequestId() + { + DWORD id = m_requestId++; + if (id < FirstRequestId) + { + // overflow, restart + id = FirstRequestId; + m_requestId = FirstRequestId + 1; + } + return id; + } + void CSimulatorFsx::updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft) { CSimulatedAircraft myAircraft(getOwnAircraft()); @@ -390,30 +404,33 @@ namespace BlackSimPlugin aircraftSituation.setBank(CAngle(-simulatorOwnAircraft.bank, CAngleUnit::deg())); aircraftSituation.setHeading(CHeading(simulatorOwnAircraft.trueHeading, CHeading::True, CAngleUnit::deg())); aircraftSituation.setGroundSpeed(CSpeed(simulatorOwnAircraft.velocity, CSpeedUnit::kts())); - aircraftSituation.setGroundElevation(CAltitude(simulatorOwnAircraft.elevation, CAltitude::MeanSeaLevel, CLengthUnit::m())); + aircraftSituation.setGroundElevation(CAltitude(simulatorOwnAircraft.elevation, CAltitude::MeanSeaLevel, CLengthUnit::ft())); aircraftSituation.setAltitude(CAltitude(simulatorOwnAircraft.altitude, CAltitude::MeanSeaLevel, CLengthUnit::ft())); - CAircraftLights lights(simulatorOwnAircraft.lightStrobe, - simulatorOwnAircraft.lightLanding, - simulatorOwnAircraft.lightTaxi, - simulatorOwnAircraft.lightBeacon, - simulatorOwnAircraft.lightNav, - simulatorOwnAircraft.lightLogo); - - QList helperList {simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0, - simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 }; + const CAircraftLights lights(simulatorOwnAircraft.lightStrobe, + simulatorOwnAircraft.lightLanding, + simulatorOwnAircraft.lightTaxi, + simulatorOwnAircraft.lightBeacon, + simulatorOwnAircraft.lightNav, + simulatorOwnAircraft.lightLogo); CAircraftEngineList engines; + const QList helperList + { + simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0, + simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 + }; + for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index) { engines.push_back(CAircraftEngine(index + 1, helperList.at(index))); } - CAircraftParts parts(lights, simulatorOwnAircraft.gearHandlePosition, - simulatorOwnAircraft.flapsHandlePosition * 100, - simulatorOwnAircraft.spoilersHandlePosition, - engines, - simulatorOwnAircraft.simOnGround); + const CAircraftParts parts(lights, simulatorOwnAircraft.gearHandlePosition, + simulatorOwnAircraft.flapsHandlePosition * 100, + simulatorOwnAircraft.spoilersHandlePosition, + engines, + simulatorOwnAircraft.simOnGround); // set values updateOwnSituation(aircraftSituation); @@ -463,6 +480,39 @@ namespace BlackSimPlugin } } + void CSimulatorFsx::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftSimData &remoteAircraftData) + { + CInterpolationHints &hints = m_hints[simObject.getCallsign()]; + + // we only need elevation near ground, in other cases we ignore it + if (remoteAircraftData.aboveGround() <= 100.0) + { + CElevationPlane elevation(remoteAircraftData.latitude, remoteAircraftData.longitude, remoteAircraftData.elevation); + elevation.setSinglePointRadius(); + + // const QString debug(hints.debugInfo(elevation)); + hints.setElevation(elevation); // update elevation + hints.setCGAboveGround({ remoteAircraftData.cgToGround, CLengthUnit::ft() }); + + // set it in the remote aircraft provider + this->updateAircraftGroundElevation(simObject.getCallsign(), elevation); + // switch to fast updates + if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_VISUAL_FRAME) + { + this->requestDataForSimObject(simObject, SIMCONNECT_PERIOD_VISUAL_FRAME); + } + } + else + { + hints.resetElevation(); + // switch to slow updates + if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_SECOND) + { + this->requestDataForSimObject(simObject, SIMCONNECT_PERIOD_SECOND); + } + } + } + void CSimulatorFsx::updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea) { CTransponder::TransponderMode newMode; @@ -475,7 +525,7 @@ namespace BlackSimPlugin newMode = sbDataArea.isStandby() ? CTransponder::StateStandby : CTransponder::ModeC; } const CSimulatedAircraft myAircraft(this->getOwnAircraft()); - bool changed = (myAircraft.getTransponderMode() != newMode); + const bool changed = (myAircraft.getTransponderMode() != newMode); if (!changed) { return; } CTransponder xpdr = myAircraft.getTransponder(); xpdr.setTransponderMode(newMode); @@ -511,7 +561,7 @@ namespace BlackSimPlugin } // P3D also has SimConnect_AIReleaseControlEx; - DWORD requestId = m_requestId++; + const DWORD requestId = obtainRequestId(); HRESULT hr = SimConnect_AIReleaseControl(m_hSimConnect, objectId, static_cast(requestId)); if (hr == S_OK) { @@ -683,6 +733,7 @@ namespace BlackSimPlugin // call in SIM SimConnect_AIRemoveObject(m_hSimConnect, static_cast(simObject.getObjectId()), static_cast(m_requestId++)); + m_hints.remove(simObject.getCallsign()); // mark in provider bool updated = updateAircraftRendered(callsign, false); @@ -809,7 +860,6 @@ namespace BlackSimPlugin // values used for position and parts bool isOnGround = false; const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); - const CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock) const QList simObjects(m_simConnectObjects.values()); for (const CSimConnectObject &simObj : simObjects) @@ -823,43 +873,13 @@ namespace BlackSimPlugin Q_ASSERT_X(simObj.hasValidRequestAndObjectId(), Q_FUNC_INFO, "Missing ids"); IInterpolator::InterpolationStatus interpolatorStatus; - const CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, simObj.isVtol(), interpolatorStatus); - - // having the onGround flag in parts forces me to obtain parts here - // which is not the smartest thing regarding performance - IInterpolator::PartsStatus partsStatus; - partsStatus.setSupportsParts(enableAircraftParts && aircraftWithParts.contains(callsign)); - CAircraftPartsList parts; - if (enableAircraftParts && partsStatus.allTrue()) - { - parts = this->m_interpolator->getPartsBeforeTime(callsign, interpolatedSituation.getMSecsSinceEpoch(), partsStatus); - } + const CInterpolationHints hints(m_hints[simObj.getCallsign()]); + const CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, hints, interpolatorStatus); if (interpolatorStatus.allTrue()) { // update situation - SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxPosition(interpolatedSituation); - - //! \fixme The onGround in parts is no ideal, as already mentioned in the discussion - // a) I am forced to read parts even if I just want to update position - // b) Unlike the other values it is not a fire and forget value, as I need it again in the next cycle - if (partsStatus.isSupportingParts() && !parts.isEmpty()) - { - // we have parts, and use the closest ground - - // \fixme onGround flag is not synchronized with positions and causes jumps during takeoff/landing. - // We need to find a better way to synchronize both. Until then, use it for a very small speed range only. - // This covers taxiing aircraft as well as a hovering helicopter. - double groundSpeedKnots = interpolatedSituation.getGroundSpeed().value(CSpeedUnit::kts()); - if (groundSpeedKnots < 50) { isOnGround = parts.front().isOnGround(); } - else { isOnGround = interpolatedSituation.isOnGroundGuessed(); } - } - else - { - isOnGround = interpolatedSituation.isOnGroundGuessed(); - } - - position.OnGround = isOnGround ? 1U : 0U; + SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxPosition(interpolatedSituation, hints); HRESULT hr = S_OK; hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition, static_cast(simObj.getObjectId()), 0, 0, @@ -873,10 +893,16 @@ namespace BlackSimPlugin if (interpolatorStatus.didInterpolationSucceed()) { + const CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock) + IInterpolator::PartsStatus partsStatus; + partsStatus.setSupportsParts(enableAircraftParts && aircraftWithParts.contains(callsign)); + // aircraft parts inside "interpolator if", as no parts can be set without situation // situation is used to anticipate parts if other client does not send them if (enableAircraftParts) { + CAircraftPartsList parts; + parts = this->m_interpolator->getPartsBeforeTime(callsign, interpolatedSituation.getMSecsSinceEpoch(), partsStatus); updateRemoteAircraftParts(simObj, parts, partsStatus, interpolatedSituation, isOnGround); // update and retrieve parts in the same step } } @@ -971,22 +997,20 @@ namespace BlackSimPlugin return hr == S_OK; } - SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxPosition(const CAircraftSituation &situation, bool guessOnGround) + SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxPosition(const CAircraftSituation &situation, const CInterpolationHints &hints) { SIMCONNECT_DATA_INITPOSITION position; position.Latitude = situation.latitude().value(CAngleUnit::deg()); position.Longitude = situation.longitude().value(CAngleUnit::deg()); - position.Altitude = situation.getAltitude().value(CLengthUnit::ft()); + position.Altitude = situation.getCorrectedAltitude(hints.getCGAboveGround()).value(CLengthUnit::ft()); + position.Heading = situation.getHeading().value(CAngleUnit::deg()); + position.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts()); + // MSFS has inverted pitch and bank angles position.Pitch = -situation.getPitch().value(CAngleUnit::deg()); position.Bank = -situation.getBank().value(CAngleUnit::deg()); - position.Heading = situation.getHeading().value(CAngleUnit::deg()); - position.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts()); - bool onGround = false; - if (guessOnGround) - { - onGround = situation.isOnGroundGuessed(); - } + + const bool onGround = situation.isOnGroundGuessed(hints.getCGAboveGround()); position.OnGround = onGround ? 1U : 0U; return position; } @@ -1047,6 +1071,21 @@ namespace BlackSimPlugin } } + bool CSimulatorFsx::requestDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period) + { + if (!simObject.hasValidRequestAndObjectId()) { return false; } + if (simObject.getSimDataPeriod() == period) { return true; } // already queried like this + + const HRESULT result = SimConnect_RequestDataOnSimObject(m_hSimConnect, simObject.getRequestId(), CSimConnectDefinitions::DataRemoteAircraftSimData, simObject.getObjectId(), period, SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_CHANGED); + if (result == S_OK) + { + m_simConnectObjects[simObject.getCallsign()].setSimDataPeriod(period); + return true; + } + CLogMessage(this).error("Cannot request data on object '%1'") << simObject.getObjectId(); + return false; + } + void CSimulatorFsx::initInternalsObject() { CSimulatorFsCommon::initInternalsObject(); @@ -1068,7 +1107,7 @@ namespace BlackSimPlugin m_syncDeferredCounter = 0; m_skipCockpitUpdateCycles = 0; m_interpolationRequest = 0; - m_requestId = 1; + m_requestId = FirstRequestId; m_dispatchErrors = 0; m_receiveExceptionCount = 0; CSimulatorFsCommon::reset(); diff --git a/src/plugins/simulator/fsx/simulatorfsx.h b/src/plugins/simulator/fsx/simulatorfsx.h index 64fdb9887..8048bdaea 100644 --- a/src/plugins/simulator/fsx/simulatorfsx.h +++ b/src/plugins/simulator/fsx/simulatorfsx.h @@ -16,7 +16,7 @@ #include "simconnectobject.h" #include "../fscommon/simulatorfscommon.h" #include "blackcore/simulator.h" -#include "blackmisc/interpolatorlinear.h" +#include "blackmisc/simulation/interpolatorlinear.h" #include "blackmisc/simulation/simulatorplugininfo.h" #include "blackmisc/simulation/simulatorsettings.h" #include "blackmisc/simulation/aircraftmodel.h" @@ -102,27 +102,6 @@ namespace BlackSimPlugin virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override; //! @} - //! Display receive exceptions? - bool stillDisplayReceiveExceptions(); - - //! Called when data about our own aircraft are received - void updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft); - - //! Update from SB client area - void updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea); - - //! An AI aircraft was added in the simulator - bool simulatorReportedObjectAdded(DWORD objectID); - - //! Simulator reported that AI aircraft was removed - bool simulatorReportedObjectRemoved(DWORD objectID); - - //! Set ID of a SimConnect object, so far we only have an request id in the object - bool setSimConnectObjectId(DWORD requestID, DWORD objectID); - - //! The simconnect related objects - const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; } - protected: //! \name Interface implementations //! @{ @@ -149,7 +128,8 @@ namespace BlackSimPlugin //! \remark kind of cleanup function, in an ideal this should never need to cleanup something BlackMisc::Aviation::CCallsignSet ps_physicallyRemoveAircraftNotInProvider(); - //! Handle that an object has been added + //! Handle that an object has been added in simulator + //! \remark checks if the object was really added after an add request and not directly removed again bool ps_deferredSimulatorReportedObjectAdded(const BlackMisc::Aviation::CCallsign &callsign); //! Try to add the aircraft currently out of bubble @@ -171,6 +151,9 @@ namespace BlackSimPlugin //! Simulator is going down void onSimExit(); + //! Get new request id, overflow safe + DWORD obtainRequestId(); + //! Init when connected HRESULT initWhenConnected(); @@ -185,10 +168,34 @@ namespace BlackSimPlugin //! Update remote airacraft parts (send to FSX) bool updateRemoteAircraftParts(const CSimConnectObject &simObj, const BlackMisc::Aviation::CAircraftPartsList &parts, - BlackMisc::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const; + BlackMisc::Simulation::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const; + + //! Called when data about our own aircraft are received + void updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft); + + //! Remote aircraft data sent from simulator + void updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftSimData &remoteAircraftData); + + //! Update from SB client area + void updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea); + + //! An AI aircraft was added in the simulator + bool simulatorReportedObjectAdded(DWORD objectID); + + //! Simulator reported that AI aircraft was removed + bool simulatorReportedObjectRemoved(DWORD objectID); + + //! Set ID of a SimConnect object, so far we only have an request id in the object + bool setSimConnectObjectId(DWORD requestID, DWORD objectID); + + //! Display receive exceptions? + bool stillDisplayReceiveExceptions(); + + //! The simconnect related objects + const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; } //! Format conversion - SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const BlackMisc::Aviation::CAircraftSituation &situation, bool guessOnGround = true); + SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Simulation::CInterpolationHints &hints); //! Sync time with user's computer void synchronizeTime(const BlackMisc::PhysicalQuantities::CTime &zuluTimeSim, const BlackMisc::PhysicalQuantities::CTime &localTimeSim); @@ -199,6 +206,9 @@ namespace BlackSimPlugin //! Reload weather settings void reloadWeatherSettings(); + //! Request data for a simObject (aka remote aircraft) + bool requestDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period = SIMCONNECT_PERIOD_SECOND); + //! FSX position as string static QString fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position); @@ -207,17 +217,19 @@ namespace BlackSimPlugin static constexpr int SkipUpdateCyclesForCockpit = 10; //!< skip x cycles before updating cockpit again static constexpr int IgnoreReceiveExceptions = 10; //!< skip exceptions when displayed more than x times + static constexpr int FirstRequestId = static_cast(CSimConnectDefinitions::RequestEndMarker); + QString m_simConnectVersion; //!< SimConnect version bool m_simConnected = false; //!< Is simulator connected? bool m_simSimulating = false; //!< Simulator running? bool m_useSbOffsets = true; //!< with SB offsets int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time int m_simConnectTimerId = -1; //!< Timer identifier - int m_skipCockpitUpdateCycles = 0; //!< Skip some update cycles to allow changes in simulator cockpit to be set + int m_skipCockpitUpdateCycles = 0; //!< skip some update cycles to allow changes in simulator cockpit to be set int m_interpolationRequest = 0; //!< current interpolation request int m_dispatchErrors = 0; //!< number of dispatched failed, \sa ps_dispatch int m_receiveExceptionCount = 0; //!< exceptions - DWORD m_requestId = 1; //!< request id + DWORD m_requestId = FirstRequestId; //!< request id, use obtainRequestId() to get id HANDLE m_hSimConnect = nullptr; //!< handle to SimConnect object CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids BlackMisc::Simulation::CSimulatedAircraftList m_outOfRealityBubble; //!< aircraft removed by FSX because they are out of reality bubble diff --git a/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp b/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp index e4e74c08f..071b08463 100644 --- a/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp +++ b/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp @@ -82,7 +82,7 @@ namespace BlackSimPlugin { case SystemEventSimStatus: { - bool running = event->dwData ? true : false; + const bool running = event->dwData ? true : false; if (running) { simulatorFsx->onSimRunning(); @@ -95,7 +95,7 @@ namespace BlackSimPlugin } case SystemEventPause: { - bool p = event->dwData ? true : false; + const bool p = event->dwData ? true : false; if (simulatorFsx->m_simPaused != p) { simulatorFsx->m_simPaused = p; @@ -110,7 +110,7 @@ namespace BlackSimPlugin } case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE: { - SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast(pData); + const SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast(pData); const DWORD objectID = event->dwData; const SIMCONNECT_SIMOBJECT_TYPE objectType = event->eObjType; if (objectType != SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT && objectType != SIMCONNECT_SIMOBJECT_TYPE_HELICOPTER) @@ -151,25 +151,37 @@ namespace BlackSimPlugin case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID: { SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast(pData); - const DWORD requestID = event->dwRequestID; - const DWORD objectID = event->dwObjectID; - bool success = simulatorFsx->setSimConnectObjectId(requestID, objectID); + const DWORD requestId = event->dwRequestID; + const DWORD objectId = event->dwObjectID; + bool success = simulatorFsx->setSimConnectObjectId(requestId, objectId); if (!success) { break; } // not an request ID of ours - success = simulatorFsx->simulatorReportedObjectAdded(objectID); - if (!success) + success = simulatorFsx->simulatorReportedObjectAdded(objectId); + if (success) { - const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectID).getAircraft()); - const CStatusMessage msg = CStatusMessage(simulatorFsx).error("Cannot add object %1") << objectID; - CLogMessage::preformatted(msg); - emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msg); + const CSimConnectObject simObject = simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectId); + HRESULT result = simulatorFsx->requestDataForSimObject(simObject); + Q_UNUSED(result); } + else + { + const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectId).getAircraft()); + const CStatusMessage msgAdd = CStatusMessage(simulatorFsx).error("Cannot add object %1") << objectId; + CLogMessage::preformatted(msgAdd); + emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msgAdd); + } + break; + } + case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE: + { + // SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *)pData; break; } case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: { SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA *) pData; - switch (pObjData->dwRequestID) + const DWORD requestId = pObjData->dwRequestID; + switch (requestId) { case CSimConnectDefinitions::RequestOwnAircraft: { @@ -203,6 +215,21 @@ namespace BlackSimPlugin break; } default: + { + static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size."); + const CSimConnectObject simObj = simulatorFsx->getSimConnectObjects().getSimObjectForRequestId(requestId); + if (simObj.hasValidRequestAndObjectId()) + { + const DWORD objectId = pObjData->dwObjectID; + const DataDefinitionRemoteAircraftSimData *remoteAircraftSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData; + // extra check, but ids should be the same + if (objectId == simObj.getObjectId()) + { + simulatorFsx->updateRemoteAircraftFromSimulator(simObj, *remoteAircraftSimData); + } + } + break; + } break; } break;