refs #789, improvements to try to solve FSX issue in driver

* more asserts to find issues
* limit number of exceptions displayed
* reset() function (there was an issue with not cleaned up values)
* using CSimConnectObjects and adjustments for the previous changes
This commit is contained in:
Klaus Basan
2016-11-07 20:22:15 +01:00
parent 9deedf1e10
commit 94d6b8d6b8
9 changed files with 379 additions and 171 deletions

View File

@@ -106,7 +106,8 @@ namespace BlackSimPlugin
{
connect(lobbyClient.data(), &CLobbyClient::disconnected, this, std::bind(&CSimulatorFs9::simulatorStatusChanged, this, 0));
this->m_interpolator = new BlackMisc::CInterpolatorLinear(remoteAircraftProvider, this);
m_defaultModel = {
m_defaultModel =
{
"Boeing 737-400",
CAircraftModel::TypeModelMatchingDefaultModel,
"B737-400 default model",
@@ -170,10 +171,13 @@ namespace BlackSimPlugin
client->start();
m_hashFs9Clients.insert(callsign, client);
updateAircraftRendered(callsign, rendered);
bool updated = updateAircraftRendered(callsign, rendered);
CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft);
remoteAircraftCopy.setRendered(rendered);
emit aircraftRenderingChanged(remoteAircraftCopy);
if (updated)
{
emit aircraftRenderingChanged(remoteAircraftCopy);
}
CLogMessage(this).info("FS9: Added aircraft %1") << callsign.toQString();
return true;
}

View File

@@ -26,7 +26,7 @@ namespace BlackSimPlugin
{
namespace Fsx
{
//! \brief Data struct of our own aircraft
//! Data struct of our own aircraft
//! \sa SimConnect variables http://msdn.microsoft.com/en-us/library/cc526981.aspx
//! \sa SimConnect events http://msdn.microsoft.com/en-us/library/cc526980.aspx
struct DataDefinitionOwnAircraft
@@ -40,12 +40,12 @@ namespace BlackSimPlugin
double velocity; //!< Ground velocity
double simOnGround; //!< Is aircraft on ground?
double lightStrobe; //!< Is strobe light on?
double lightLanding; //!< Is landing light on?
double lightTaxi; //!< Is taxi light on?
double lightBeacon; //!< Is beacon light on?
double lightNav; //!< Is nav light on?
double lightLogo; //!< Is logo light on?
double lightStrobe; //!< Is strobe light on?
double lightLanding; //!< Is landing light on?
double lightTaxi; //!< Is taxi light on?
double lightBeacon; //!< Is beacon light on?
double lightNav; //!< Is nav light on?
double lightLogo; //!< Is logo light on?
double transponderCode; //!< Transponder Code
double com1ActiveMHz; //!< COM1 active frequency
@@ -73,22 +73,22 @@ namespace BlackSimPlugin
//! Data struct of remote aircraft parts
struct DataDefinitionRemoteAircraftParts
{
double lightStrobe; //!< Is strobe light on?
double lightLanding; //!< Is landing light on?
// double lightTaxi; //!< Is taxi light on?
double lightBeacon; //!< Is beacon light on?
double lightNav; //!< Is nav light on?
double lightLogo; //!< Is logo light on?
double flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent
double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent
double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent
double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent
double gearHandlePosition; //!< Gear handle position
double spoilersHandlePosition; //!< Spoilers out?
double engine1Combustion; //!< Engine 1 combustion flag
double engine2Combustion; //!< Engine 2 combustion flag
double engine3Combustion; //!< Engine 3 combustion flag
double engine4Combustion; //!< Engine 4 combustion flag
double lightStrobe; //!< Is strobe light on?
double lightLanding; //!< Is landing light on?
// double lightTaxi; //!< Is taxi light on?
double lightBeacon; //!< Is beacon light on?
double lightNav; //!< Is nav light on?
double lightLogo; //!< Is logo light on?
double flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent
double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent
double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent
double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent
double gearHandlePosition; //!< Gear handle position
double spoilersHandlePosition; //!< Spoilers out?
double engine1Combustion; //!< Engine 1 combustion flag
double engine2Combustion; //!< Engine 2 combustion flag
double engine3Combustion; //!< Engine 3 combustion flag
double engine4Combustion; //!< Engine 4 combustion flag
};
//! Data struct simulator environment
@@ -134,7 +134,6 @@ namespace BlackSimPlugin
class CSimConnectDefinitions
{
public:
//! SimConnect definiton IDs
enum DataDefiniton
{
@@ -168,7 +167,6 @@ namespace BlackSimPlugin
static QString getLogCategory() { return "swift.fsx.simconnect"; }
private:
//! Initialize data definition for our own aircraft
static HRESULT initOwnAircraft(const HANDLE hSimConnect);

View File

@@ -40,6 +40,9 @@ namespace BlackSimPlugin
//! Simulated aircraft (as added)
const BlackMisc::Simulation::CSimulatedAircraft &getAircraft() const { return m_aircraft; }
//! Simulated aircraft model string
const QString &getAircraftModelString() const { return m_aircraft.getModelString(); }
//! Set Simconnect request id
void setRequestId(int id) { m_requestId = id; }

View File

@@ -19,6 +19,7 @@
#include "blackmisc/aviation/airportlist.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/threadutils.h"
#include "blackmisc/verify.h"
#include "blackmisc/simulation/fscommon/fscommonutil.h"
#include <QTimer>
@@ -81,12 +82,10 @@ namespace BlackSimPlugin
bool CSimulatorFsx::connectTo()
{
if (this->isConnected()) { return true; }
this->reset();
if (FAILED(SimConnect_Open(&m_hSimConnect, sApp->swiftVersionChar(), nullptr, 0, 0, 0)))
{
// reset state as expected for unconnected
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
m_simConnected = false;
m_simSimulating = false;
return false;
}
if (m_useFsuipc) { this->m_fsuipc->connect(); } // FSUIPC too
@@ -102,25 +101,14 @@ namespace BlackSimPlugin
bool CSimulatorFsx::disconnectFrom()
{
if (!m_simConnected) { return true; }
// stop mapper init
//! \todo mapper shutdown in FSX, review keep it?
// mapperInstance()->gracefulShutdown();
if (m_simconnectTimerId)
{
killTimer(m_simconnectTimerId);
}
if (m_simconnectTimerId) { killTimer(m_simconnectTimerId); }
if (m_hSimConnect)
{
SimConnect_Close(m_hSimConnect);
m_hSimConnect = nullptr;
}
m_simConnected = false;
m_simSimulating = false;
m_simconnectTimerId = -1;
reset();
// emit status and disconnect FSUIPC
CSimulatorFsCommon::disconnectFrom();
@@ -136,8 +124,26 @@ namespace BlackSimPlugin
Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string");
if (callsign.isEmpty()) { return false; }
const bool aircraftAlreadyExistsInSim = this->m_simConnectObjects.contains(callsign);
if (aircraftAlreadyExistsInSim)
// check if we have to do something
if (m_simConnectObjects.contains(callsign))
{
const CSimConnectObject simObj = m_simConnectObjects[callsign];
if (simObj.isPendingAdded())
{
return true; // already pending
}
else
{
// same model, nothing will change, otherwise add again when removed
if (simObj.getAircraft().getModel() != newRemoteAircraft.getModel())
{
m_aircraftToAddAgainWhenRemoved.push_back(newRemoteAircraft);
}
return false;
}
}
if (!m_pendingAircraftToAdd.isEmpty() || m_simConnectObjects.containsPendingAdd())
{
const CSimConnectObject simObj = m_simConnectObjects[callsign];
if (simObj.isPendingAdded())
@@ -164,11 +170,17 @@ namespace BlackSimPlugin
// initial position
setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(addedAircraft.getSituation());
const QByteArray m = aircraftModel.getModelString().toLocal8Bit();
const int requestId = m_requestId++;
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation());
const QString modelString(addedAircraft.getModelString());
const QByteArray m(modelString.toLocal8Bit());
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{
CLogMessage(this).debug() << "physicallyAddRemoteAircraft" << callsign.toQString() << "request" << requestId << "model" << modelString;
CLogMessage(this).debug() << "initial position" << fsxPositionToString(initialPosition);
}
const int requestId = m_requestId;
++m_requestId;
HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
if (hr != S_OK)
{
@@ -275,22 +287,13 @@ namespace BlackSimPlugin
SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK;
switch (message.getSeverity())
{
case CStatusMessage::SeverityDebug:
return;
case CStatusMessage::SeverityInfo:
type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN;
break;
case CStatusMessage::SeverityWarning:
type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW;
break;
case CStatusMessage::SeverityError:
type = SIMCONNECT_TEXT_TYPE_PRINT_RED;
break;
case CStatusMessage::SeverityDebug: return;
case CStatusMessage::SeverityInfo: type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN; break;
case CStatusMessage::SeverityWarning: type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW; break;
case CStatusMessage::SeverityError: type = SIMCONNECT_TEXT_TYPE_PRINT_RED; break;
}
HRESULT hr = SimConnect_Text(
m_hSimConnect, type, 7.5, EventTextMessage, static_cast<DWORD>(m.size()),
m.data()
);
HRESULT hr = SimConnect_Text(m_hSimConnect, type, 7.5, EventTextMessage,
static_cast<DWORD>(m.size()), m.data());
Q_UNUSED(hr);
}
@@ -312,6 +315,12 @@ namespace BlackSimPlugin
return CCallsignSet(this->m_simConnectObjects.keys());
}
bool CSimulatorFsx::stillDisplayReceiveExceptions()
{
m_receiveExceptionCount++;
return m_receiveExceptionCount < IgnoreReceiveExceptions;
}
void CSimulatorFsx::setSimConnected()
{
m_simConnected = true;
@@ -404,8 +413,7 @@ namespace BlackSimPlugin
simulatorOwnAircraft.lightLogo);
QList<bool> helperList {simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0,
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0
};
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 };
CAircraftEngineList engines;
for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
@@ -436,16 +444,16 @@ namespace BlackSimPlugin
// updates
com1.setFrequencyActive(CFrequency(simulatorOwnAircraft.com1ActiveMHz, CFrequencyUnit::MHz()));
com1.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com1StandbyMHz, CFrequencyUnit::MHz()));
bool changedCom1 = myAircraft.getCom1System() != com1;
const bool changedCom1 = myAircraft.getCom1System() != com1;
this->m_simCom1 = com1;
com2.setFrequencyActive(CFrequency(simulatorOwnAircraft.com2ActiveMHz, CFrequencyUnit::MHz()));
com2.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com2StandbyMHz, CFrequencyUnit::MHz()));
bool changedCom2 = myAircraft.getCom2System() != com2;
const bool changedCom2 = myAircraft.getCom2System() != com2;
this->m_simCom2 = com2;
transponder.setTransponderCode(simulatorOwnAircraft.transponderCode);
bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode());
const bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode());
if (changedCom1 || changedCom2 || changedXpr)
{
@@ -486,60 +494,86 @@ namespace BlackSimPlugin
this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), xpdr, this->identifier());
}
bool CSimulatorFsx::aiAircraftWasAddedInSimulator(DWORD requestID, DWORD objectID)
bool CSimulatorFsx::simulatorReportedObjectAdded(DWORD objectID)
{
if (!this->setSimConnectObjectID(requestID, objectID)) { return false; }
const CSimConnectObject simObject = this->getSimObjectForObjectId(objectID);
const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID);
const CCallsign callsign(simObject.getCallsign());
if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty()) { return false; }
bool ok = false;
if (simObject.hasValidRequestAndObjectId() && !simObject.getCallsign().isEmpty())
Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "already confirmed");
m_simConnectObjects[callsign].setConfirmedAdded(true);
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{
CLogMessage(this).debug() << "Adding AI" << callsign.toQString() << "confirmed" << "id" << static_cast<int>(objectID) << "model" << simObject.getAircraftModelString();
}
SimConnect_AIReleaseControl(m_hSimConnect, objectID, requestID);
// P3D also has SimConnect_AIReleaseControlEx;
const int requestId = m_requestId++;
HRESULT hr = SimConnect_AIReleaseControl(m_hSimConnect, objectID, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
if (hr == S_OK)
{
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeLat, 1,
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAlt, 1,
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAtt, 1,
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
}
else
{
CLogMessage(this).error("Adding AI %1 failed") << callsign.toQString();
}
// optimistic approach, as the aircraft is not yet really in the SIM
// its generation has been just requested
this->updateAircraftRendered(simObject.getCallsign(), true);
const bool updated = this->updateAircraftRendered(simObject.getCallsign(), true);
if (updated)
{
emit aircraftRenderingChanged(simObject.getAircraft());
ok = true;
}
return true;
}
bool CSimulatorFsx::simulatorReportedObjectRemoved(DWORD objectID)
{
const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID);
if (!simObject.hasValidRequestAndObjectId()) { return false; } // object id from somewhere else
const CCallsign callsign(simObject.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
bool ok = false;
if (simObject.isPendingRemoved())
{
// good case, we can remove object
}
else
{
// object was removed but not requested by us
CLogMessage(this).warning("Removed %1 from simulator, but was not initiated by us: %1 '%2' object id %3") << callsign.toQString() << simObject.getAircraftModelString() << static_cast<int>(objectID);
}
// in all cases we remove
const int c = m_simConnectObjects.remove(callsign);
m_pendingAircraftToAdd.removeByCallsign(callsign);
ok = c > 0;
CLogMessage(this).info("FSX: Removed aircraft '%1'") << simObject.getCallsign().toQString();
const bool updated = this->updateAircraftRendered(simObject.getCallsign(), false);
if (updated)
{
emit aircraftRenderingChanged(simObject.getAircraft());
}
// models we have to add again after removing
if (m_aircraftToAddAgainWhenRemoved.containsCallsign(callsign))
{
const CSimulatedAircraft aircraftAddAgain = m_aircraftToAddAgainWhenRemoved.findFirstByCallsign(callsign);
QTimer::singleShot(1000, this, [ = ] { this->physicallyAddRemoteAircraft(aircraftAddAgain); });
}
return ok;
}
bool CSimulatorFsx::setSimConnectObjectID(DWORD requestID, DWORD objectID)
bool CSimulatorFsx::setSimConnectObjectId(DWORD requestID, DWORD objectID)
{
// First check, if this request id belongs to us
const int requestIntId = static_cast<int>(requestID);
auto it = std::find_if(m_simConnectObjects.begin(), m_simConnectObjects.end(), [requestIntId](const CSimConnectObject & obj) { return obj.getRequestId() == requestIntId; });
if (it == m_simConnectObjects.end()) { return false; }
// belongs to us
it->setObjectId(static_cast<int>(objectID));
return true;
}
CCallsign CSimulatorFsx::getCallsignForObjectId(DWORD objectID) const
{
return getSimObjectForObjectId(objectID).getCallsign();
}
CSimConnectObject CSimulatorFsx::getSimObjectForObjectId(DWORD objectID) const
{
const int objectIntId = static_cast<int>(objectID);
for (const CSimConnectObject &simObject : m_simConnectObjects.values())
{
if (simObject.getObjectId() == objectIntId)
{
return simObject;
}
}
return CSimConnectObject();
return this->m_simConnectObjects.setSimConnectObjectId(static_cast<int>(requestID), static_cast<int>(objectID));
}
void CSimulatorFsx::timerEvent(QTimerEvent *event)
@@ -571,7 +605,7 @@ namespace BlackSimPlugin
if (m_useFsuipc && m_fsuipc)
{
CSimulatedAircraft fsuipcAircraft(getOwnAircraft());
//! \todo split in high / low frequency reads
//! \fixme split in high / low frequency reads
bool ok = m_fsuipc->read(fsuipcAircraft, true, true, true);
if (ok)
{
@@ -584,34 +618,58 @@ namespace BlackSimPlugin
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign)
{
// only remove from sim
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thred");
if (!m_simConnectObjects.contains(callsign)) { return false; }
this->physicallyRemoveRemoteAircraft(m_simConnectObjects.value(callsign));
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thread");
if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft
if (m_pendingAircraftToAdd.removeByCallsign(callsign) > 0) { return true; } // was in queue to be added
if (!m_simConnectObjects.contains(callsign)) { return false; } // already fully removed or not yet added
CSimConnectObject &simObject = m_simConnectObjects[callsign];
if (simObject.isPendingRemoved()) { return true; }
if (simObject.isPendingAdded())
{
// problem: we try to delete an aircraft just requested to be added
return false; //! \todo improve
}
simObject.setPendingRemoved(true);
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{
CLogMessage(this).debug() << "physicallyRemoveRemoteAircraft" << callsign.toQString();
}
// call in SIM
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(m_requestId++));
// mark in provider
bool updated = updateAircraftRendered(callsign, false);
if (updated)
{
CSimulatedAircraft aircraft(simObject.getAircraft());
aircraft.setRendered(false);
emit aircraftRenderingChanged(aircraft);
}
// cleanup function, actually this should not be needed
QTimer::singleShot(100, this, &CSimulatorFsx::ps_physicallyRemoveAircraftNotInProvider);
// bye
return true;
}
int CSimulatorFsx::physicallyRemoveAllRemoteAircraft()
{
if (m_simConnectObjects.isEmpty()) { return 0; }
QList<CCallsign> callsigns(m_simConnectObjects.keys());
const QList<CCallsign> callsigns(m_simConnectObjects.keys());
int r = 0;
for (const CCallsign &cs : callsigns)
{
if (physicallyRemoveRemoteAircraft(cs)) { r++; }
}
clearAllAircraft();
return r;
}
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject)
{
CCallsign callsign(simObject.getCallsign());
m_simConnectObjects.remove(callsign);
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(simObject.getRequestId()));
updateAircraftRendered(callsign, false);
CLogMessage(this).info("FSX: Removed aircraft '%1'") << simObject.getCallsign().toQString();
return true;
}
HRESULT CSimulatorFsx::initEvents()
{
HRESULT hr = S_OK;
@@ -706,25 +764,29 @@ namespace BlackSimPlugin
// values used for position and parts
bool isOnGround = false;
qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock)
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)
{
if (simObj.getObjectId() < 1) { continue; }
// happending if aircraft is not yet added to SIM or to be deleted
if (simObj.isPendingAdded()) { continue; }
if (simObj.isPendingRemoved()) { continue; }
const CCallsign callsign(simObj.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
Q_ASSERT_X(simObj.hasValidRequestAndObjectId(), Q_FUNC_INFO, "Missing ids");
IInterpolator::InterpolationStatus interpolatorStatus;
CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, simObj.isVtol(), 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.supportsParts = aircraftWithParts.contains(callsign);
partsStatus.setSupportsParts(aircraftWithParts.contains(callsign));
CAircraftPartsList parts;
if (partsStatus.supportsParts)
if (partsStatus.allTrue())
{
parts = this->m_interpolator->getPartsBeforeTime(callsign, currentTimestamp, partsStatus);
}
@@ -732,13 +794,12 @@ namespace BlackSimPlugin
if (interpolatorStatus.allTrue())
{
// update situation
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxInitPosition(interpolatedSituation);
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxPosition(interpolatedSituation);
//! \todo The onGround in parts is nuts, as already mentioned in the discussion
// Currently ignored here, only guessing which is faster as aircraft without parts can just be
//! \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.supportsParts && !parts.isEmpty())
if (partsStatus.isSupportingParts() && !parts.isEmpty())
{
// we have parts, and use the closest ground
isOnGround = parts.front().isOnGround();
@@ -753,11 +814,14 @@ namespace BlackSimPlugin
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition,
static_cast<SIMCONNECT_OBJECT_ID>(simObj.getObjectId()), 0, 0,
sizeof(SIMCONNECT_DATA_INITPOSITION), &position);
if (hr != S_OK) { CLogMessage(this).warning("Failed so set position on SimObject '%1' callsign: '%2'") << simObj.getObjectId() << callsign; }
if (hr != S_OK)
{
CLogMessage(this).warning("Failed so set position on SimObject '%1' callsign: '%2'") << simObj.getObjectId() << callsign;
}
} // interpolation data
if (interpolatorStatus.interpolationSucceeded)
if (interpolatorStatus.didInterpolationSucceed())
{
// aircraft parts
// inside "interpolator if", as no parts can be sent without position
@@ -765,7 +829,7 @@ namespace BlackSimPlugin
}
} // all callsigns
qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
const qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
m_statsUpdateAircraftTimeTotalMs += dt;
m_statsUpdateAircraftCountMs++;
m_statsUpdateAircraftTimeAvgMs = m_statsUpdateAircraftTimeTotalMs / m_statsUpdateAircraftCountMs;
@@ -773,9 +837,11 @@ namespace BlackSimPlugin
bool CSimulatorFsx::updateRemoteAircraftParts(const CSimConnectObject &simObj, const CAircraftPartsList &parts, IInterpolator::PartsStatus partsStatus, const CAircraftSituation &interpolatedSituation, bool isOnGround) const
{
if (!simObj.hasValidRequestAndObjectId()) { return false; }
// set parts
DataDefinitionRemoteAircraftParts ddRemoteAircraftParts;
if (partsStatus.supportsParts)
if (partsStatus.isSupportingParts())
{
// parts is supported, but do we need to update?
if (parts.isEmpty()) { return false; }
@@ -928,6 +994,47 @@ namespace BlackSimPlugin
}
}
void CSimulatorFsx::reset()
{
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
m_simConnected = false;
m_simSimulating = false;
m_simconnectTimerId = -1;
CSimulatorFsCommon::reset();
}
void CSimulatorFsx::clearAllAircraft()
{
m_simConnectObjects.clear();
CSimulatorFsCommon::clearAllAircraft();
}
QString CSimulatorFsx::fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position)
{
const QString positionStr("Lat: %1 lng: %2 alt: %3ft pitch: %4 bank: %5 hdg: %6 airspeed: %7kts onGround: %8");
return positionStr.
arg(position.Latitude).arg(position.Longitude).arg(position.Altitude).
arg(position.Pitch).arg(position.Bank).arg(position.Heading).arg(position.Airspeed).arg(position.OnGround);
}
CCallsignSet CSimulatorFsx::getCallsignsMissingInProvider() const
{
CCallsignSet simObjectCallsigns(m_simConnectObjects.keys());
CCallsignSet providerCallsigns(this->getAircraftInRangeCallsigns());
return simObjectCallsigns.difference(providerCallsigns);
}
CCallsignSet CSimulatorFsx::ps_physicallyRemoveAircraftNotInProvider()
{
const CCallsignSet toBeRemoved(getCallsignsMissingInProvider());
if (toBeRemoved.isEmpty()) { return toBeRemoved; }
for (const CCallsign &callsign : toBeRemoved)
{
physicallyRemoveRemoteAircraft(callsign);
}
return toBeRemoved;
}
CSimulatorFsxListener::CSimulatorFsxListener(const CSimulatorPluginInfo &info) :
ISimulatorListener(info),
m_timer(new QTimer(this))

View File

@@ -102,6 +102,9 @@ 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(DataDefinitionOwnAircraft simulatorOwnAircraft);
@@ -109,17 +112,16 @@ namespace BlackSimPlugin
void updateOwnAircraftFromSimulator(DataDefinitionClientAreaSb sbDataArea);
//! An AI aircraft was added in the simulator
//! \remark that AI aircraft was previously request by requestID
bool aiAircraftWasAddedInSimulator(DWORD requestID, DWORD objectID);
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);
bool setSimConnectObjectId(DWORD requestID, DWORD objectID);
//! Find which callsign belongs to the object id
BlackMisc::Aviation::CCallsign getCallsignForObjectId(DWORD objectID) const;
//! Find which callsign belongs to the object id
CSimConnectObject getSimObjectForObjectId(DWORD objectID) const;
//! The simconnect related objects
const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
protected:
//! \copydoc BlackCore::ISimulator::isConnected()
@@ -136,6 +138,10 @@ namespace BlackSimPlugin
//! Dispatch SimConnect messages
void ps_dispatch();
//! Remove aircraft not in provider anymore
//! \remark kind of cleanup function, in an ideal this should never need to cleanup something
BlackMisc::Aviation::CCallsignSet ps_physicallyRemoveAircraftNotInProvider();
private:
//! Call this method to declare the simulator connected
void setSimConnected();
@@ -152,9 +158,6 @@ namespace BlackSimPlugin
//! Simulator is going down
void onSimExit();
//! Remove a remote aircraft
bool physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject);
//! Init when connected
HRESULT initWhenConnected();
@@ -172,7 +175,7 @@ namespace BlackSimPlugin
BlackMisc::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const;
//! Format conversion
SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxInitPosition(const BlackMisc::Aviation::CAircraftSituation &situation);
SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const BlackMisc::Aviation::CAircraftSituation &situation, bool guessOnGround = true);
//! Sync time with user's computer
void synchronizeTime(const BlackMisc::PhysicalQuantities::CTime &zuluTimeSim, const BlackMisc::PhysicalQuantities::CTime &localTimeSim);
@@ -183,9 +186,22 @@ namespace BlackSimPlugin
//! Reload weather settings
void reloadWeatherSettings();
//! Reset values when restarted
virtual void reset() override;
//! Clear all aircraft lists
virtual void clearAllAircraft() override;
//! FSX position as string
static QString fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position);
//! Get the callsigns which are no longer in the provider, but still in m_simConnectObjects
BlackMisc::Aviation::CCallsignSet getCallsignsMissingInProvider() const;
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
bool m_simConnected = false; //!< Is simulator connected?
bool m_simSimulating = false; //!< Simulator running?
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
@@ -193,10 +209,10 @@ namespace BlackSimPlugin
int m_interpolationRequest = 0; //!< current interpolation request
int m_interpolationsSkipped = 0; //!< number of skipped interpolation request
int m_requestId = 1; //!< request id
int m_dispatchErrors = 0; //!< numer of dispatched failed, \sa ps_dispatch
int m_dispatchErrors = 0; //!< number of dispatched failed, \sa ps_dispatch
int m_receiveExceptionCount = 0; //!< exceptions
HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object
QHash<BlackMisc::Aviation::CCallsign, CSimConnectObject> m_simConnectObjects;
CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids
BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last
BlackMisc::CSetting<BlackCore::Simulator::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &CSimulatorFsx::reloadWeatherSettings };
};

View File

@@ -50,6 +50,11 @@ namespace BlackSimPlugin
}
case SIMCONNECT_RECV_ID_EXCEPTION:
{
if (!simulatorFsx->stillDisplayReceiveExceptions())
{
break;
}
SIMCONNECT_RECV_EXCEPTION *exception = (SIMCONNECT_RECV_EXCEPTION *)pData;
QString ex;
const int exceptionId = static_cast<int>(exception->dwException);
@@ -57,17 +62,19 @@ namespace BlackSimPlugin
const int index = static_cast<int>(exception->dwIndex);
const int data = static_cast<int>(cbData);
ex.sprintf("Exception=%d SendID=%d Index=%d cbData=%d", exceptionId, sendId, index, data);
if (exceptionId == SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE)
switch (exceptionId)
{
// means we have problems with an AI aircraft
//! \todo find out how to obtain the id here so I can get callsign
CCallsign cs = simulatorFsx->getCallsignForObjectId(data);
if (!cs.isEmpty())
case SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE:
case SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID:
{
ex += " callsign: ";
ex += cs.toQString();
//! \fixme do not know how to obtain the object id which failed. Can I get it?
}
break;
default:
break;
}
CLogMessage(simulatorFsx).error("Caught FSX simConnect exception: %1 %2")
<< CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException)
<< ex;
@@ -114,11 +121,24 @@ namespace BlackSimPlugin
case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
{
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)
{
break;
}
// such an object is not necessarily one of ours
// for instance, I always see object 5 when I start the simulator
if (!simulatorFsx->getSimConnectObjects().isKnownSimObjectId(objectID)) break;
switch (event->uEventID)
{
case SystemEventObjectAdded:
// added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID
// adding here cause trouble
break;
case SystemEventObjectRemoved:
simulatorFsx->simulatorReportedObjectRemoved(objectID);
break;
default:
break;
@@ -131,6 +151,7 @@ namespace BlackSimPlugin
switch (event->uEventID)
{
case SystemEventFrame:
// doing interpolation
simulatorFsx->onSimFrame();
break;
default:
@@ -143,13 +164,16 @@ namespace BlackSimPlugin
SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData);
const DWORD requestID = event->dwRequestID;
const DWORD objectID = event->dwObjectID;
const bool success = simulatorFsx->aiAircraftWasAddedInSimulator(requestID, objectID);
bool success = simulatorFsx->setSimConnectObjectId(requestID, objectID);
if (!success) { break; } // not an request ID of ours
success = simulatorFsx->simulatorReportedObjectAdded(objectID);
if (!success)
{
CLogMessage(simulatorFsx).warning("Cannot find CSimConnectObject for request %1") << requestID;
const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimObjectForObjectId(objectID).getAircraft());
const QString msg("Object id for request " + QString::number(requestID) + " not avialable");
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, CStatusMessage(simulatorFsx, CStatusMessage::SeverityError, msg));
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);
}
break;
}