refs #840, FSX driver: get ground elevation from simulator

* fixed wrong request id
* made functions private where possible
* added data definitions for simobject data
This commit is contained in:
Klaus Basan
2016-12-21 22:43:45 +01:00
committed by Mathew Sutcliffe
parent be297d8ccf
commit 93a18f433c
7 changed files with 253 additions and 126 deletions

View File

@@ -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<CSimConnectDefinitions *>(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<CSimConnectDefinitions *>(nullptr)).error("SimConnect error: initRemoteAircraftSimData %1") << hr;
}
return hr;
}
@@ -162,6 +176,5 @@ namespace BlackSimPlugin
}
return hr;
}
} // namespace
} // namespace

View File

@@ -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);

View File

@@ -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));

View File

@@ -16,8 +16,7 @@
#include "simconnect/SimConnect.h"
#include <QSharedPointer>
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;

View File

@@ -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<bool> 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<bool> 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<SIMCONNECT_DATA_REQUEST_ID>(requestId));
if (hr == S_OK)
{
@@ -683,6 +733,7 @@ namespace BlackSimPlugin
// call in SIM
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(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<CSimConnectObject> 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<SIMCONNECT_OBJECT_ID>(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();

View File

@@ -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<int>(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

View File

@@ -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<SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *>(pData);
const SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast<SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *>(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<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(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;