Ref T275, improved tracing for FSX

* getStatisticsSimulatorSpecific for simulator specific traces/logs
* trace CSimulatorFsxCommon::SimConnectProc times
* trace which receive id is handled in SimConnectProc
* allow to limit aircraft updates (max FPS)
* handle airport updates outside SimConnectProc
This commit is contained in:
Klaus Basan
2018-06-08 22:03:05 +02:00
parent bdf58ff538
commit 4975ecd712
7 changed files with 242 additions and 44 deletions

View File

@@ -196,6 +196,9 @@ namespace BlackCore
//! \remark needs to be overridden if the concrete driver supports such an option //! \remark needs to be overridden if the concrete driver supports such an option
virtual bool requestElevation(const BlackMisc::Geo::ICoordinateGeodetic &reference, const BlackMisc::Aviation::CCallsign &callsign) override; virtual bool requestElevation(const BlackMisc::Geo::ICoordinateGeodetic &reference, const BlackMisc::Aviation::CCallsign &callsign) override;
//! Allows to print out simulator specific statistics
virtual QString getStatisticsSimulatorSpecific() const { return QString(); }
//! \copydoc BlackMisc::IProvider::asQObject //! \copydoc BlackMisc::IProvider::asQObject
virtual QObject *asQObject() override { return this; } virtual QObject *asQObject() override { return this; }

View File

@@ -244,15 +244,15 @@ namespace BlackCore
CAirportList CSimulatorCommon::getAirportsInRange() const CAirportList CSimulatorCommon::getAirportsInRange() const
{ {
// default implementation // default implementation
if (this->isShuttingDown()) { return CAirportList(); }
if (!sApp || !sApp->hasWebDataServices()) { return CAirportList(); } if (!sApp || !sApp->hasWebDataServices()) { return CAirportList(); }
if (sApp->isShuttingDown()) { return CAirportList(); }
CAirportList airports = sApp->getWebDataServices()->getAirports(); const CAirportList airports = sApp->getWebDataServices()->getAirports();
if (airports.isEmpty()) { return airports; } if (airports.isEmpty()) { return airports; }
const CCoordinateGeodetic ownPosition = this->getOwnAircraftPosition(); const CCoordinateGeodetic ownPosition = this->getOwnAircraftPosition();
airports = airports.findClosest(maxAirportsInRange(), ownPosition); CAirportList airportInRange = airports.findClosest(maxAirportsInRange(), ownPosition);
if (m_autoCalcAirportDistance) { airports.calculcateAndUpdateRelativeDistanceAndBearing(ownPosition); } if (m_autoCalcAirportDistance) { airportInRange.calculcateAndUpdateRelativeDistanceAndBearing(ownPosition); }
return airports; return airportInRange;
} }
void CSimulatorCommon::setWeatherActivated(bool activated) void CSimulatorCommon::setWeatherActivated(bool activated)
@@ -276,6 +276,53 @@ namespace BlackCore
return reverseModel; return reverseModel;
} }
bool CSimulatorCommon::isUpdateAircraftLimited(qint64 timestamp)
{
if (!m_limitUpdateAircraft) { return false; }
const bool hasToken = m_limitUpdateAircraftBucket.tryConsume(1, timestamp);
return !hasToken;
}
bool CSimulatorCommon::isUpdateAircraftLimitedWithStats(qint64 startTime)
{
const bool limited = this->isUpdateAircraftLimited(startTime);
this->setStatsRemoteAircraftUpdate(startTime, limited);
return limited;
}
bool CSimulatorCommon::limitToUpdatesPerSecond(int numberPerSecond)
{
if (numberPerSecond < 1)
{
m_limitUpdateAircraft = false;
return false;
}
int tokens = 0.1 * numberPerSecond; // 100ms
do
{
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(100); break; }
tokens = 0.25 * numberPerSecond; // 250ms
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(250); break; }
tokens = 0.5 * numberPerSecond; // 500ms
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(500); break; }
tokens = numberPerSecond;
m_limitUpdateAircraftBucket.setInterval(1000);
}
while (false);
m_limitUpdateAircraftBucket.setCapacityAndTokensToRefill(tokens);
m_limitUpdateAircraft = true;
return true;
}
QString CSimulatorCommon::updateAircraftLimitationInfo() const
{
if (!m_limitUpdateAircraft) { return QStringLiteral("not limited"); }
static const QString limInfo("Limited %1 times with %2/secs.");
return limInfo.arg(m_statsUpdateAircraftLimited).arg(m_limitUpdateAircraftBucket.getTokensPerSecond());
}
void CSimulatorCommon::onSwiftDbAllDataRead() void CSimulatorCommon::onSwiftDbAllDataRead()
{ {
// void, can be overridden in specialized drivers // void, can be overridden in specialized drivers
@@ -579,9 +626,18 @@ namespace BlackCore
this->logicallyRemoveRemoteAircraft(cs); this->logicallyRemoveRemoteAircraft(cs);
} }
} }
return false; return false;
} }
if (part1.startsWith("limit"))
{
const int perSecond = parser.toInt(2, -1);
this->limitToUpdatesPerSecond(perSecond);
CLogMessage(this).info("Remote aircraft updates limitations: %1") << this->updateAircraftLimitationInfo();
return true;
}
// driver specific cmd line arguments // driver specific cmd line arguments
return this->parseDetails(parser); return this->parseDetails(parser);
} }
@@ -590,6 +646,7 @@ namespace BlackCore
{ {
if (CSimpleCommandParser::registered("BlackCore::CSimulatorCommon")) { return; } if (CSimpleCommandParser::registered("BlackCore::CSimulatorCommon")) { return; }
CSimpleCommandParser::registerCommand({".drv", "alias: .driver .plugin"}); CSimpleCommandParser::registerCommand({".drv", "alias: .driver .plugin"});
CSimpleCommandParser::registerCommand({".drv limit number/secs.", "limit updates to number per second (0..off)"});
CSimpleCommandParser::registerCommand({".drv logint callsign", "log interpolator for callsign"}); CSimpleCommandParser::registerCommand({".drv logint callsign", "log interpolator for callsign"});
CSimpleCommandParser::registerCommand({".drv logint off", "no log information for interpolator"}); CSimpleCommandParser::registerCommand({".drv logint off", "no log information for interpolator"});
CSimpleCommandParser::registerCommand({".drv logint write", "write interpolator log to file"}); CSimpleCommandParser::registerCommand({".drv logint write", "write interpolator log to file"});
@@ -613,6 +670,7 @@ namespace BlackCore
m_statsPhysicallyRemovedAircraft = 0; m_statsPhysicallyRemovedAircraft = 0;
m_statsLastUpdateAircraftRequestedMs = 0; m_statsLastUpdateAircraftRequestedMs = 0;
m_statsUpdateAircraftRequestedDeltaMs = 0; m_statsUpdateAircraftRequestedDeltaMs = 0;
m_statsUpdateAircraftLimited = 0;
} }
CStatusMessageList CSimulatorCommon::debugVerifyStateAfterAllAircraftRemoved() const CStatusMessageList CSimulatorCommon::debugVerifyStateAfterAllAircraftRemoved() const
@@ -662,7 +720,7 @@ namespace BlackCore
m_clampedLogMsg.remove(callsign); m_clampedLogMsg.remove(callsign);
} }
void CSimulatorCommon::setStatsRemoteAircraftUpdate(qint64 startTime) void CSimulatorCommon::setStatsRemoteAircraftUpdate(qint64 startTime, bool limited)
{ {
const qint64 now = QDateTime::currentMSecsSinceEpoch(); const qint64 now = QDateTime::currentMSecsSinceEpoch();
const qint64 dt = now - startTime; const qint64 dt = now - startTime;
@@ -671,9 +729,11 @@ namespace BlackCore
m_statsUpdateAircraftRuns++; m_statsUpdateAircraftRuns++;
m_statsUpdateAircraftTimeAvgMs = static_cast<double>(m_statsUpdateAircraftTimeTotalMs) / static_cast<double>(m_statsUpdateAircraftRuns); m_statsUpdateAircraftTimeAvgMs = static_cast<double>(m_statsUpdateAircraftTimeTotalMs) / static_cast<double>(m_statsUpdateAircraftRuns);
m_updateRemoteAircraftInProgress = false; m_updateRemoteAircraftInProgress = false;
m_statsLastUpdateAircraftRequestedMs = startTime;
if (m_statsMaxUpdateTimeMs < dt) { m_statsMaxUpdateTimeMs = dt; } if (m_statsMaxUpdateTimeMs < dt) { m_statsMaxUpdateTimeMs = dt; }
if (m_statsLastUpdateAircraftRequestedMs > 0) { m_statsUpdateAircraftRequestedDeltaMs = startTime - m_statsLastUpdateAircraftRequestedMs; } if (m_statsLastUpdateAircraftRequestedMs > 0) { m_statsUpdateAircraftRequestedDeltaMs = startTime - m_statsLastUpdateAircraftRequestedMs; }
m_statsLastUpdateAircraftRequestedMs = startTime; if (limited) { m_statsUpdateAircraftLimited++; }
} }
bool CSimulatorCommon::isEqualLastSent(const CAircraftSituation &compare) const bool CSimulatorCommon::isEqualLastSent(const CAircraftSituation &compare) const
@@ -795,19 +855,22 @@ namespace BlackCore
CAirportList CSimulatorCommon::getWebServiceAirports() const CAirportList CSimulatorCommon::getWebServiceAirports() const
{ {
if (this->isShuttingDown()) { return CAirportList(); }
if (!sApp->hasWebDataServices()) { return CAirportList(); } if (!sApp->hasWebDataServices()) { return CAirportList(); }
return sApp->getWebDataServices()->getAirports(); return sApp->getWebDataServices()->getAirports();
} }
CAirport CSimulatorCommon::getWebServiceAirport(const CAirportIcaoCode &icao) const CAirport CSimulatorCommon::getWebServiceAirport(const CAirportIcaoCode &icao) const
{ {
if (this->isShuttingDown()) { return CAirport(); }
if (!sApp->hasWebDataServices()) { return CAirport(); } if (!sApp->hasWebDataServices()) { return CAirport(); }
return sApp->getWebDataServices()->getAirports().findFirstByIcao(icao); return sApp->getWebDataServices()->getAirports().findFirstByIcao(icao);
} }
void CSimulatorCommon::rapOnRecalculatedRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot) void CSimulatorCommon::rapOnRecalculatedRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot)
{ {
if (!this->isConnected()) return; if (!this->isConnected()) { return; }
if (this->isShuttingDown()) { return; }
this->onRecalculatedRenderedAircraft(snapshot); this->onRecalculatedRenderedAircraft(snapshot);
} }

View File

@@ -33,6 +33,7 @@
#include "blackmisc/pq/length.h" #include "blackmisc/pq/length.h"
#include "blackmisc/pq/time.h" #include "blackmisc/pq/time.h"
#include "blackmisc/pq/units.h" #include "blackmisc/pq/units.h"
#include "blackmisc/tokenbucket.h"
#include "blackmisc/connectionguard.h" #include "blackmisc/connectionguard.h"
namespace BlackMisc namespace BlackMisc
@@ -93,6 +94,7 @@ namespace BlackCore
//! @{ //! @{
//! <pre> //! <pre>
//! .drv unload unload plugin BlackCore::CSimulatorCommon //! .drv unload unload plugin BlackCore::CSimulatorCommon
//! .drv limit number limit the number of updates BlackCore::CSimulatorCommon
//! .drv logint callsign log interpolator for callsign BlackCore::CSimulatorCommon //! .drv logint callsign log interpolator for callsign BlackCore::CSimulatorCommon
//! .drv logint off no log information for interpolator BlackCore::CSimulatorCommon //! .drv logint off no log information for interpolator BlackCore::CSimulatorCommon
//! .drv logint write write interpolator log to file BlackCore::CSimulatorCommon //! .drv logint write write interpolator log to file BlackCore::CSimulatorCommon
@@ -119,7 +121,7 @@ namespace BlackCore
static void registerHelp(); static void registerHelp();
//! Reset the statistics counters //! Reset the statistics counters
void resetAircraftStatistics(); virtual void resetAircraftStatistics();
//! Counter added aircraft //! Counter added aircraft
int getStatisticsPhysicallyAddedAircraft() const { return m_statsPhysicallyAddedAircraft; } int getStatisticsPhysicallyAddedAircraft() const { return m_statsPhysicallyAddedAircraft; }
@@ -152,6 +154,9 @@ namespace BlackCore
//! \remark public only for log. displays //! \remark public only for log. displays
QString latestLoggedDataFormatted(const BlackMisc::Aviation::CCallsign &cs) const; QString latestLoggedDataFormatted(const BlackMisc::Aviation::CCallsign &cs) const;
//! Info about update aircraft limitations
QString updateAircraftLimitationInfo() const;
protected: protected:
//! Constructor //! Constructor
CSimulatorCommon(const BlackMisc::Simulation::CSimulatorPluginInfo &info, CSimulatorCommon(const BlackMisc::Simulation::CSimulatorPluginInfo &info,
@@ -246,7 +251,7 @@ namespace BlackCore
void removedClampedLog(const BlackMisc::Aviation::CCallsign &callsign); void removedClampedLog(const BlackMisc::Aviation::CCallsign &callsign);
//! Update stats and flags //! Update stats and flags
void setStatsRemoteAircraftUpdate(qint64 startTime); void setStatsRemoteAircraftUpdate(qint64 startTime, bool limited = false);
//! Equal to last sent situation //! Equal to last sent situation
bool isEqualLastSent(const BlackMisc::Aviation::CAircraftSituation &compare) const; bool isEqualLastSent(const BlackMisc::Aviation::CAircraftSituation &compare) const;
@@ -268,6 +273,7 @@ namespace BlackCore
bool m_updateRemoteAircraftInProgress = false; //!< currently updating remote aircraft bool m_updateRemoteAircraftInProgress = false; //!< currently updating remote aircraft
int m_timerId = -1; //!< dispatch timer id int m_timerId = -1; //!< dispatch timer id
int m_statsUpdateAircraftRuns = 0; //!< statistics update count int m_statsUpdateAircraftRuns = 0; //!< statistics update count
int m_statsUpdateAircraftLimited = 0; //!< skipped because of max.update limitations
double m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics average update time double m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics average update time
qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics total update time qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics total update time
qint64 m_statsCurrentUpdateTimeMs = 0; //!< statistics current update time qint64 m_statsCurrentUpdateTimeMs = 0; //!< statistics current update time
@@ -284,6 +290,19 @@ namespace BlackCore
// some optional functionality which can be used by the simulators as needed // some optional functionality which can be used by the simulators as needed
BlackMisc::Simulation::CSimulatedAircraftList m_addAgainAircraftWhenRemoved; //!< add this model again when removed, normally used to change model BlackMisc::Simulation::CSimulatedAircraftList m_addAgainAircraftWhenRemoved; //!< add this model again when removed, normally used to change model
// limit the update aircraft to a maximum per second
BlackMisc::CTokenBucket m_limitUpdateAircraftBucket { 5, 100, 5 }; //!< means 50 per second
bool m_limitUpdateAircraft = false; //!< limit the update frequency by using BlackMisc::CTokenBucket
//! Limit reached (max number of updates by token bucket if enabled)
bool isUpdateAircraftLimited(qint64 timestamp = -1);
//! Limited as CSimulatorCommon::isUpdateAircraftLimited plus updating statistics
bool isUpdateAircraftLimitedWithStats(qint64 startTime = -1);
//! Limit to updates per seconds
bool limitToUpdatesPerSecond(int numberPerSecond);
// weather // weather
bool m_isWeatherActivated = false; //!< Is simulator weather activated? bool m_isWeatherActivated = false; //!< Is simulator weather activated?
BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last

View File

@@ -255,6 +255,16 @@ namespace BlackSimPlugin
return msgs; return msgs;
} }
QString CSimulatorFsxCommon::getStatisticsSimulatorSpecific() const
{
static const QString specificInfo("dispatch (cur/max): %1ms %2ms %3 %4 simData#: %5");
return specificInfo.
arg(m_dispatchTimeMs).arg(m_dispatchMaxTimeMs).
arg(CSimConnectUtilities::simConnectReceiveIdToString(m_dispatchMaxTimeReceiveId),
CSimConnectDefinitions::requestToString(m_dispatchMaxTimeRequest)).
arg(m_requestSimObjectDataCount);
}
bool CSimulatorFsxCommon::requestElevation(const ICoordinateGeodetic &reference, const CCallsign &callsign) bool CSimulatorFsxCommon::requestElevation(const ICoordinateGeodetic &reference, const CCallsign &callsign)
{ {
Q_UNUSED(callsign); Q_UNUSED(callsign);
@@ -304,12 +314,29 @@ namespace BlackSimPlugin
m_traceAutoTs = -1; m_traceAutoTs = -1;
} }
void CSimulatorFsxCommon::resetAircraftStatistics()
{
m_dispatchMaxTimeMs = -1;
m_dispatchTimeMs = -1;
m_requestSimObjectDataCount = 0;
m_dispatchLastReceiveId = SIMCONNECT_RECV_ID_NULL;
m_dispatchMaxTimeReceiveId = SIMCONNECT_RECV_ID_NULL;
m_dispatchLastRequest = CSimConnectDefinitions::RequestEndMarker;
m_dispatchMaxTimeRequest = CSimConnectDefinitions::RequestEndMarker;
CSimulatorPluginCommon::resetAircraftStatistics();
}
bool CSimulatorFsxCommon::stillDisplayReceiveExceptions() bool CSimulatorFsxCommon::stillDisplayReceiveExceptions()
{ {
m_receiveExceptionCount++; m_receiveExceptionCount++;
return m_receiveExceptionCount < IgnoreReceiveExceptions; return m_receiveExceptionCount < IgnoreReceiveExceptions;
} }
CSimConnectObject CSimulatorFsxCommon::getSimObjectForObjectId(DWORD objectId) const
{
return this->getSimConnectObjects().getSimObjectForObjectId(objectId);
}
void CSimulatorFsxCommon::setSimConnected() void CSimulatorFsxCommon::setSimConnected()
{ {
m_simConnected = true; m_simConnected = true;
@@ -387,11 +414,7 @@ namespace BlackSimPlugin
void CSimulatorFsxCommon::onSimFrame() void CSimulatorFsxCommon::onSimFrame()
{ {
if (m_updateRemoteAircraftInProgress) if (m_updateRemoteAircraftInProgress) { return; }
{
return;
}
QPointer<CSimulatorFsxCommon> myself(this); QPointer<CSimulatorFsxCommon> myself(this);
QTimer::singleShot(0, this, [ = ] QTimer::singleShot(0, this, [ = ]
{ {
@@ -551,7 +574,7 @@ namespace BlackSimPlugin
void CSimulatorFsxCommon::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftSimData &remoteAircraftData) void CSimulatorFsxCommon::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftSimData &remoteAircraftData)
{ {
// Near ground we use faster updates // Near ground we use faster updates
if (remoteAircraftData.aboveGround() <= 100.0) if (remoteAircraftData.aboveGroundFt() <= 100.0)
{ {
// switch to fast updates // switch to fast updates
if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_VISUAL_FRAME) if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_VISUAL_FRAME)
@@ -570,12 +593,12 @@ namespace BlackSimPlugin
// CElevationPlane: deg, deg, feet // CElevationPlane: deg, deg, feet
// we only remember near ground // we only remember near ground
const CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupPerCallsignOrDefault(simObject.getCallsign()); if (remoteAircraftData.aboveGroundFt() < 250)
if (simObject.getLastInterpolatedSituation(setup.getInterpolatorMode()).canLikelySkipNearGroundInterpolation()) { return; } {
CElevationPlane elevation(remoteAircraftData.latitudeDeg, remoteAircraftData.longitudeDeg, remoteAircraftData.elevationFt);
CElevationPlane elevation(remoteAircraftData.latitudeDeg, remoteAircraftData.longitudeDeg, remoteAircraftData.elevationFt); elevation.setSinglePointRadius();
elevation.setSinglePointRadius(); this->rememberElevationAndCG(simObject.getCallsign(), elevation, CLength(remoteAircraftData.cgToGroundFt, CLengthUnit::ft()));
this->rememberElevationAndCG(simObject.getCallsign(), elevation, CLength(remoteAircraftData.cgToGroundFt, CLengthUnit::ft())); }
} }
void CSimulatorFsxCommon::updatProbeFromSimulator(const CCallsign &callsign, const DataDefinitionRemoteAircraftSimData &remoteAircraftData) void CSimulatorFsxCommon::updatProbeFromSimulator(const CCallsign &callsign, const DataDefinitionRemoteAircraftSimData &remoteAircraftData)
@@ -769,6 +792,7 @@ namespace BlackSimPlugin
bool CSimulatorFsxCommon::simulatorReportedObjectRemoved(DWORD objectID) bool CSimulatorFsxCommon::simulatorReportedObjectRemoved(DWORD objectID)
{ {
if (this->isShuttingDown()) { return false; }
const CSimConnectObject simObject = m_simConnectObjects.getSimObjectForObjectId(objectID); const CSimConnectObject simObject = m_simConnectObjects.getSimObjectForObjectId(objectID);
if (!simObject.hasValidRequestAndObjectId()) { return false; } // object id from somewhere else if (!simObject.hasValidRequestAndObjectId()) { return false; } // object id from somewhere else
const CCallsign callsign(simObject.getCallsign()); const CCallsign callsign(simObject.getCallsign());
@@ -908,10 +932,29 @@ namespace BlackSimPlugin
{ {
// call CSimulatorFsxCommon::SimConnectProc or specialized P3D version // call CSimulatorFsxCommon::SimConnectProc or specialized P3D version
Q_ASSERT_X(m_dispatchProc, Q_FUNC_INFO, "Missing DispatchProc"); Q_ASSERT_X(m_dispatchProc, Q_FUNC_INFO, "Missing DispatchProc");
// statistics
const qint64 start = QDateTime::currentMSecsSinceEpoch();
m_dispatchLastReceiveId = SIMCONNECT_RECV_ID_NULL;
m_dispatchLastRequest = CSimConnectDefinitions::RequestEndMarker;
// process
const HRESULT hr = SimConnect_CallDispatch(m_hSimConnect, m_dispatchProc, this); const HRESULT hr = SimConnect_CallDispatch(m_hSimConnect, m_dispatchProc, this);
// statistics
m_dispatchTimeMs = QDateTime::currentMSecsSinceEpoch() - start;
if (m_dispatchMaxTimeMs < m_dispatchTimeMs)
{
m_dispatchMaxTimeMs = m_dispatchTimeMs;
m_dispatchMaxTimeReceiveId = m_dispatchLastReceiveId;
m_dispatchMaxTimeRequest = m_dispatchLastRequest;
}
// error handling
if (hr != S_OK) if (hr != S_OK)
{ {
m_dispatchErrors++; m_dispatchErrors++;
this->triggerAutoTraceSendId();
if (m_dispatchErrors == 2) if (m_dispatchErrors == 2)
{ {
// 2nd time, an error / avoid multiple messages // 2nd time, an error / avoid multiple messages
@@ -1290,6 +1333,7 @@ namespace BlackSimPlugin
// values used for position and parts // values used for position and parts
const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
if (this->isUpdateAircraftLimitedWithStats(currentTimestamp)) { return; }
m_updateRemoteAircraftInProgress = true; m_updateRemoteAircraftInProgress = true;
// interpolation for all remote aircraft // interpolation for all remote aircraft
@@ -1364,6 +1408,40 @@ namespace BlackSimPlugin
return this->sendRemoteAircraftPartsToSimulator(simObject, ddRemoteAircraftPartsWithoutLights, parts.getAdjustedLights()); return this->sendRemoteAircraftPartsToSimulator(simObject, ddRemoteAircraftPartsWithoutLights, parts.getAdjustedLights());
} }
void CSimulatorFsxCommon::triggerUpdateAirports(const CAirportList &airports)
{
if (this->isShuttingDown()) { return; }
if (airports.isEmpty()) { return; }
QPointer<CSimulatorFsxCommon> myself(this);
QTimer::singleShot(0, this, [ = ]
{
if (!myself) { return; }
this->updateAirports(airports);
});
}
void CSimulatorFsxCommon::updateAirports(const CAirportList &airports)
{
if (airports.isEmpty()) { return; }
static const CLength maxDistance(200.0, CLengthUnit::NM());
const CCoordinateGeodetic posAircraft(this->getOwnAircraftPosition());
for (const CAirport &airport : airports)
{
CAirport consolidatedAirport(airport);
const CLength d = consolidatedAirport.calculcateAndUpdateRelativeDistanceAndBearing(posAircraft);
if (d > maxDistance) { continue; }
consolidatedAirport.updateMissingParts(this->getWebServiceAirport(airport.getIcao()));
m_airportsInRangeFromSimulator.replaceOrAddByIcao(consolidatedAirport);
if (m_airportsInRangeFromSimulator.size() > this->maxAirportsInRange())
{
m_airportsInRangeFromSimulator.sortByDistanceToOwnAircraft();
m_airportsInRangeFromSimulator.truncate(this->maxAirportsInRange());
}
}
}
bool CSimulatorFsxCommon::sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, DataDefinitionRemoteAircraftPartsWithoutLights &ddRemoteAircraftPartsWithoutLights, const CAircraftLights &lights) bool CSimulatorFsxCommon::sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, DataDefinitionRemoteAircraftPartsWithoutLights &ddRemoteAircraftPartsWithoutLights, const CAircraftLights &lights)
{ {
Q_ASSERT(m_hSimConnect); Q_ASSERT(m_hSimConnect);
@@ -1563,10 +1641,13 @@ namespace BlackSimPlugin
if (result == S_OK && m_simConnectObjects.contains(simObject.getCallsign())) if (result == S_OK && m_simConnectObjects.contains(simObject.getCallsign()))
{ {
m_requestSimObjectDataCount++;
if (this->isTracingSendId()) { this->traceSendId(simObject.getObjectId(), Q_FUNC_INFO);} if (this->isTracingSendId()) { this->traceSendId(simObject.getObjectId(), Q_FUNC_INFO);}
m_simConnectObjects[simObject.getCallsign()].setSimDataPeriod(period); m_simConnectObjects[simObject.getCallsign()].setSimDataPeriod(period);
return true; return true;
} }
// failure
CLogMessage(this).error("Cannot request simulator data on object '%1'") << simObject.getObjectId(); CLogMessage(this).error("Cannot request simulator data on object '%1'") << simObject.getObjectId();
return false; return false;
} }

View File

@@ -129,6 +129,7 @@ namespace BlackSimPlugin
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override; virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;
virtual void clearAllRemoteAircraftData() override; virtual void clearAllRemoteAircraftData() override;
virtual BlackMisc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const override; virtual BlackMisc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const override;
virtual QString getStatisticsSimulatorSpecific() const override;
//! @} //! @}
//! \copydoc BlackMisc::Simulation::ISimulationEnvironmentProvider::requestElevation //! \copydoc BlackMisc::Simulation::ISimulationEnvironmentProvider::requestElevation
@@ -140,8 +141,12 @@ namespace BlackSimPlugin
//! Set tracing on/off //! Set tracing on/off
void setTractingSendId(bool trace); void setTractingSendId(bool trace);
//! \copydoc BlackCore::CSimulatorCommon::resetAircraftStatistics
virtual void resetAircraftStatistics() override;
protected: protected:
//! SimConnect Callback //! SimConnect callback
//! \note all tasks called in this function (i.e, all called functions) must perform fast or shall be called asynchronously
static void CALLBACK SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext); static void CALLBACK SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);
//! \name Interface implementations //! \name Interface implementations
@@ -278,6 +283,12 @@ namespace BlackSimPlugin
//! Update remote aircraft parts (send to FSX) //! Update remote aircraft parts (send to FSX)
bool updateRemoteAircraftParts(const CSimConnectObject &simObject, const BlackMisc::Simulation::CInterpolationResult &result); bool updateRemoteAircraftParts(const CSimConnectObject &simObject, const BlackMisc::Simulation::CInterpolationResult &result);
//! Calling CSimulatorFsxCommon::updateAirports
void triggerUpdateAirports(const BlackMisc::Aviation::CAirportList &airports);
//! Update airports from simulator
void updateAirports(const BlackMisc::Aviation::CAirportList &airports);
//! Send parts to simulator //! Send parts to simulator
//! \remark does not send if there is no change //! \remark does not send if there is no change
bool sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, DataDefinitionRemoteAircraftPartsWithoutLights &ddRemoteAircraftParts, const BlackMisc::Aviation::CAircraftLights &lights); bool sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, DataDefinitionRemoteAircraftPartsWithoutLights &ddRemoteAircraftParts, const BlackMisc::Aviation::CAircraftLights &lights);
@@ -323,9 +334,12 @@ namespace BlackSimPlugin
//! Display receive exceptions? //! Display receive exceptions?
bool stillDisplayReceiveExceptions(); bool stillDisplayReceiveExceptions();
//! The simconnect related objects //! The SimConnect related objects
const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; } const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
//! The SimConnect object for idxs
CSimConnectObject getSimObjectForObjectId(DWORD objectId) const;
//! The simconnect related probes //! The simconnect related probes
const CSimConnectObjects &getSimConnectProbes() const { return m_simConnectProbes; } const CSimConnectObjects &getSimConnectProbes() const { return m_simConnectProbes; }
@@ -400,16 +414,29 @@ namespace BlackSimPlugin
qint64 m_simulatingChangedTs = -1; //!< timestamp, when simulating changed (used to avoid jitter) qint64 m_simulatingChangedTs = -1; //!< timestamp, when simulating changed (used to avoid jitter)
int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time
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
// tracing dispatch performance
int m_dispatchErrors = 0; //!< number of dispatched failed, \sa dispatch int m_dispatchErrors = 0; //!< number of dispatched failed, \sa dispatch
int m_receiveExceptionCount = 0; //!< exceptions qint64 m_dispatchTimeMs = -1;
QList<TraceFsxSendId> m_sendIdTraces; //!< Send id traces for debugging qint64 m_dispatchMaxTimeMs = -1;
SIMCONNECT_RECV_ID m_dispatchLastReceiveId = SIMCONNECT_RECV_ID_NULL; //!< last receive id from dispatching
SIMCONNECT_RECV_ID m_dispatchMaxTimeReceiveId = SIMCONNECT_RECV_ID_NULL; //!< receive id corresponding to max.time
CSimConnectDefinitions::Request m_dispatchLastRequest = CSimConnectDefinitions::RequestEndMarker; //!< request id if any
CSimConnectDefinitions::Request m_dispatchMaxTimeRequest = CSimConnectDefinitions::RequestEndMarker; //!< request id corresponding to max.time
// sending via SimConnect
QList<TraceFsxSendId> m_sendIdTraces; //!< Send id traces for debugging
int m_receiveExceptionCount = 0; //!< exceptions
int m_requestSimObjectDataCount = 0; //!< requested SimObjects
// objects
CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids
CSimConnectObjects m_simConnectProbes; //!< AI terrain probes CSimConnectObjects m_simConnectProbes; //!< AI terrain probes
CSimConnectObjects m_simConnectObjectsPositionAndPartsTraces; //!< position/parts received, but object not yet added, excluded, disabled etc. CSimConnectObjects m_simConnectObjectsPositionAndPartsTraces; //!< position/parts received, but object not yet added, excluded, disabled etc.
SIMCONNECT_DATA_REQUEST_ID m_requestIdSimData = static_cast<SIMCONNECT_DATA_REQUEST_ID>(RequestIdSimDataStart); //!< request id, use obtainRequestIdForSimData() to get id SIMCONNECT_DATA_REQUEST_ID m_requestIdSimData = static_cast<SIMCONNECT_DATA_REQUEST_ID>(RequestIdSimDataStart); //!< request id, use obtainRequestIdForSimData() to get id
SIMCONNECT_DATA_REQUEST_ID m_requestIdProbe = static_cast<SIMCONNECT_DATA_REQUEST_ID>(RequestIdTerrainProbeStart); //!< request id, use obtainRequestIdForSimData() to get id SIMCONNECT_DATA_REQUEST_ID m_requestIdProbe = static_cast<SIMCONNECT_DATA_REQUEST_ID>(RequestIdTerrainProbeStart); //!< request id, use obtainRequestIdForProbe() to get id
BlackMisc::Simulation::CSimulatedAircraftList m_addPendingAircraft; //!< aircraft awaiting to be added BlackMisc::Simulation::CSimulatedAircraftList m_addPendingAircraft; //!< aircraft awaiting to be added
QTimer m_addPendingSimObjTimer; //!< updating of sim objects awaiting to be added QTimer m_addPendingSimObjTimer; //!< updating of SimObjects awaiting to be added
}; };
//! Listener for FSX //! Listener for FSX

View File

@@ -33,8 +33,13 @@ namespace BlackSimPlugin
{ {
void CALLBACK CSimulatorFsxCommon::SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext) void CALLBACK CSimulatorFsxCommon::SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext)
{ {
// IMPORTANT:
// all tasks called in this function (ie all called functions) must perform fast or shall be called asynchronously
CSimulatorFsxCommon *simulatorFsxP3D = static_cast<CSimulatorFsxCommon *>(pContext); CSimulatorFsxCommon *simulatorFsxP3D = static_cast<CSimulatorFsxCommon *>(pContext);
switch (pData->dwID) const SIMCONNECT_RECV_ID recvId = static_cast<SIMCONNECT_RECV_ID>(pData->dwID);
simulatorFsxP3D->m_dispatchLastReceiveId = recvId;
switch (recvId)
{ {
case SIMCONNECT_RECV_ID_OPEN: case SIMCONNECT_RECV_ID_OPEN:
{ {
@@ -210,11 +215,13 @@ namespace BlackSimPlugin
{ {
const SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA *) pData; const SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA *) pData;
const DWORD requestId = pObjData->dwRequestID; const DWORD requestId = pObjData->dwRequestID;
switch (requestId) switch (requestId)
{ {
case CSimConnectDefinitions::RequestOwnAircraft: case CSimConnectDefinitions::RequestOwnAircraft:
{ {
static_assert(sizeof(DataDefinitionOwnAircraft) == 31 * sizeof(double), "DataDefinitionOwnAircraft has an incorrect size."); static_assert(sizeof(DataDefinitionOwnAircraft) == 31 * sizeof(double), "DataDefinitionOwnAircraft has an incorrect size.");
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestOwnAircraft;
const DataDefinitionOwnAircraft *ownAircaft = (DataDefinitionOwnAircraft *)&pObjData->dwData; const DataDefinitionOwnAircraft *ownAircaft = (DataDefinitionOwnAircraft *)&pObjData->dwData;
simulatorFsxP3D->updateOwnAircraftFromSimulator(*ownAircaft); simulatorFsxP3D->updateOwnAircraftFromSimulator(*ownAircaft);
break; break;
@@ -222,14 +229,14 @@ namespace BlackSimPlugin
case CSimConnectDefinitions::RequestOwnAircraftTitle: case CSimConnectDefinitions::RequestOwnAircraftTitle:
{ {
const DataDefinitionOwnAircraftModel *dataDefinitionModel = (DataDefinitionOwnAircraftModel *) &pObjData->dwData; const DataDefinitionOwnAircraftModel *dataDefinitionModel = (DataDefinitionOwnAircraftModel *) &pObjData->dwData;
CAircraftModel model; simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestOwnAircraftTitle;
model.setModelString(dataDefinitionModel->title); const CAircraftModel model(dataDefinitionModel->title, CAircraftModel::TypeOwnSimulatorModel);
model.setModelType(CAircraftModel::TypeOwnSimulatorModel);
simulatorFsxP3D->reverseLookupAndUpdateOwnAircraftModel(model); simulatorFsxP3D->reverseLookupAndUpdateOwnAircraftModel(model);
break; break;
} }
case CSimConnectDefinitions::RequestSimEnvironment: case CSimConnectDefinitions::RequestSimEnvironment:
{ {
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestSimEnvironment;
const DataDefinitionSimEnvironment *simEnv = (DataDefinitionSimEnvironment *) &pObjData->dwData; const DataDefinitionSimEnvironment *simEnv = (DataDefinitionSimEnvironment *) &pObjData->dwData;
if (simulatorFsxP3D->isTimeSynchronized()) if (simulatorFsxP3D->isTimeSynchronized())
{ {
@@ -249,7 +256,8 @@ namespace BlackSimPlugin
if (CSimulatorFsxCommon::isRequestForSimData(requestId)) if (CSimulatorFsxCommon::isRequestForSimData(requestId))
{ {
static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size."); static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size.");
const CSimConnectObject simObj = simulatorFsxP3D->getSimConnectObjects().getSimObjectForObjectId(objectId); simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestRangeForSimData;
const CSimConnectObject simObj = simulatorFsxP3D->getSimObjectForObjectId(objectId);
if (!simObj.hasValidRequestAndObjectId()) { break; } if (!simObj.hasValidRequestAndObjectId()) { break; }
const DataDefinitionRemoteAircraftSimData *remoteAircraftSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData; const DataDefinitionRemoteAircraftSimData *remoteAircraftSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData;
// extra check, but ids should be the same // extra check, but ids should be the same
@@ -261,6 +269,7 @@ namespace BlackSimPlugin
else if (CSimulatorFsxCommon::isRequestForProbe(requestId)) else if (CSimulatorFsxCommon::isRequestForProbe(requestId))
{ {
static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size."); static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size.");
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestRangeForProbe;
const CSimConnectObject probeObj = simulatorFsxP3D->getSimConnectProbes().getSimObjectForObjectId(objectId); const CSimConnectObject probeObj = simulatorFsxP3D->getSimConnectProbes().getSimObjectForObjectId(objectId);
if (!probeObj.hasValidRequestAndObjectId()) { break; } if (!probeObj.hasValidRequestAndObjectId()) { break; }
const DataDefinitionRemoteAircraftSimData *probeSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData; const DataDefinitionRemoteAircraftSimData *probeSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData;
@@ -275,6 +284,7 @@ namespace BlackSimPlugin
else if (CSimulatorFsxCommon::isRequestForLights(requestId)) else if (CSimulatorFsxCommon::isRequestForLights(requestId))
{ {
static_assert(sizeof(DataDefinitionRemoteAircraftLights) == 8 * sizeof(double), "DataDefinitionRemoteAircraftLights has an incorrect size."); static_assert(sizeof(DataDefinitionRemoteAircraftLights) == 8 * sizeof(double), "DataDefinitionRemoteAircraftLights has an incorrect size.");
simulatorFsxP3D->m_dispatchLastRequest = CSimConnectDefinitions::RequestRangeForLights;
const CSimConnectObject simObj = simulatorFsxP3D->getSimConnectObjects().getSimObjectForObjectId(objectId); const CSimConnectObject simObj = simulatorFsxP3D->getSimConnectObjects().getSimObjectForObjectId(objectId);
if (!simObj.hasValidRequestAndObjectId()) break; if (!simObj.hasValidRequestAndObjectId()) break;
const DataDefinitionRemoteAircraftLights *remoteAircraftLights = (DataDefinitionRemoteAircraftLights *)&pObjData->dwData; const DataDefinitionRemoteAircraftLights *remoteAircraftLights = (DataDefinitionRemoteAircraftLights *)&pObjData->dwData;
@@ -299,9 +309,8 @@ namespace BlackSimPlugin
} }
case SIMCONNECT_RECV_ID_AIRPORT_LIST: case SIMCONNECT_RECV_ID_AIRPORT_LIST:
{ {
static const CLength maxDistance(200.0, CLengthUnit::NM());
const CCoordinateGeodetic posAircraft(simulatorFsxP3D->getOwnAircraftPosition());
const SIMCONNECT_RECV_AIRPORT_LIST *pAirportList = (SIMCONNECT_RECV_AIRPORT_LIST *) pData; const SIMCONNECT_RECV_AIRPORT_LIST *pAirportList = (SIMCONNECT_RECV_AIRPORT_LIST *) pData;
CAirportList simAirports;
for (unsigned i = 0; i < pAirportList->dwArraySize; ++i) for (unsigned i = 0; i < pAirportList->dwArraySize; ++i)
{ {
const SIMCONNECT_DATA_FACILITY_AIRPORT *pFacilityAirport = pAirportList->rgData + i; const SIMCONNECT_DATA_FACILITY_AIRPORT *pFacilityAirport = pAirportList->rgData + i;
@@ -311,17 +320,12 @@ namespace BlackSimPlugin
if (!CAirportIcaoCode::isValidIcaoDesignator(icao)) { continue; } // tiny airfields/strips in simulator if (!CAirportIcaoCode::isValidIcaoDesignator(icao)) { continue; } // tiny airfields/strips in simulator
if (CAirportIcaoCode::containsNumbers(icao)) { continue; } // tiny airfields/strips in simulator if (CAirportIcaoCode::containsNumbers(icao)) { continue; } // tiny airfields/strips in simulator
const CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, pFacilityAirport->Altitude); const CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, pFacilityAirport->Altitude);
CAirport airport(CAirportIcaoCode(icao), pos); const CAirport airport(CAirportIcaoCode(icao), pos);
const CLength d = airport.calculcateAndUpdateRelativeDistanceAndBearing(posAircraft); simAirports.push_back(airport);
if (d > maxDistance) { continue; }
airport.updateMissingParts(simulatorFsxP3D->getWebServiceAirport(icao));
simulatorFsxP3D->m_airportsInRangeFromSimulator.replaceOrAddByIcao(airport);
} }
if (!simAirports.isEmpty())
if (simulatorFsxP3D->m_airportsInRangeFromSimulator.size() > simulatorFsxP3D->maxAirportsInRange())
{ {
simulatorFsxP3D->m_airportsInRangeFromSimulator.sortByDistanceToOwnAircraft(); simulatorFsxP3D->triggerUpdateAirports(simAirports); // real "work" outside SimConnectProc
simulatorFsxP3D->m_airportsInRangeFromSimulator.truncate(simulatorFsxP3D->maxAirportsInRange());
} }
break; // SIMCONNECT_RECV_ID_AIRPORT_LIST break; // SIMCONNECT_RECV_ID_AIRPORT_LIST
} }

View File

@@ -35,6 +35,7 @@ namespace BlackSimPlugin
QObject *parent) : QObject *parent) :
CSimulatorFsxCommon(info, ownAircraftProvider, remoteAircraftProvider, weatherGridProvider, clientProvider, parent) CSimulatorFsxCommon(info, ownAircraftProvider, remoteAircraftProvider, weatherGridProvider, clientProvider, parent)
{ {
// set build/sim specific SimConnectProc, which is the FSX SimConnectProc on WIN32 systems
if (CBuildConfig::isCompiledWithP3DSupport() && CBuildConfig::isRunningOnWindowsNtPlatform() && CBuildConfig::buildWordSize() == 64) if (CBuildConfig::isCompiledWithP3DSupport() && CBuildConfig::isRunningOnWindowsNtPlatform() && CBuildConfig::buildWordSize() == 64)
{ {
m_dispatchProc = &CSimulatorP3D::SimConnectProc; m_dispatchProc = &CSimulatorP3D::SimConnectProc;