Reflecting discussed changes for interpolation performance refs #386

(based on FSX testing)
* Only send changed situation to SIM
* Split sending of parts / situations
* Only send parts with a reduced frequency (means slower as positions)
* Mark geodetic height as null for default values (the value is usually unavailable)
* Fixed altitude to MSL for network data
* Trace which aircrafts support aircraft parts via network
* Renamed insert_fron push_front (as proposed by Roland)

Status quo / lessons learnt
* On slower PCs jitter is still noticed for interpolated aircraft.
* Running interpolation in an independent process (aka core, not in GUI) reduced load dependencies
  => it seems to make sense to run driver in own thread
* The onGround flag in parts seems clumsy as it required to retrieve parts for position updates
* In interpolation performance really matters
This commit is contained in:
Klaus Basan
2015-02-26 21:47:28 +01:00
parent ca6cd9c063
commit eca8c5b637
21 changed files with 376 additions and 320 deletions

View File

@@ -120,9 +120,13 @@ namespace BlackCore
std::function<void(const CCallsign &)> removedAircraftSlot
)
{
bool s1 = connect(this, &CAirspaceMonitor::addedRemoteAircraftSituation, situationSlot);
// bool s1 = connect(this, &CAirspaceMonitor::addedRemoteAircraftSituation, situationSlot);
bool s1 = connect(this->m_network, &INetwork::aircraftPositionUpdate, situationSlot);
Q_ASSERT(s1);
bool s2 = connect(this, &CAirspaceMonitor::addedRemoteAircraftParts, partsSlot);
Q_ASSERT(s2);
bool s3 = connect(this, &CAirspaceMonitor::removedRemoteAircraft, removedAircraftSlot);
Q_ASSERT(s3);
return s1 && s2 && s3;
}
@@ -747,16 +751,18 @@ namespace BlackCore
if (c > 0) { ps_sendReadyForModelMatching(callsign, 1); }
}
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CCallsign &callsign, const CAircraftSituation &situation, const CTransponder &transponder)
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
if (!this->m_connected) { return; }
CCallsign callsign(situation.getCallsign());
Q_ASSERT(!callsign.isEmpty());
// store situation history
CAircraftSituation situationWithCallsign(situation);
situationWithCallsign.setCallsign(callsign);
// this->m_aircraftSituations.insert_front(situationWithCallsign);
// this->m_aircraftSituations.insert_front(situation);
// this->m_aircraftSituations.removeOlderThanNowMinusOffset(AircraftSituationsRemovedOffsetMs);
emit this->addedRemoteAircraftSituation(situation);
bool exists = this->m_aircraftInRange.containsCallsign(callsign);
if (!exists)
@@ -829,7 +835,6 @@ namespace BlackCore
this->m_aircraftWatchdog.resetCallsign(callsign);
}
emit this->addedRemoteAircraftSituation(situationWithCallsign);
emit this->changedAircraftInRange();
}

View File

@@ -201,7 +201,7 @@ namespace BlackCore
private slots:
//! Create aircraft in range, this is the only place where a new aircraft should be added
void ps_aircraftUpdateReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder);
void ps_aircraftUpdateReceived(const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder);
void ps_realNameReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &realname);
void ps_capabilitiesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, quint32 flags);

View File

@@ -35,48 +35,19 @@ namespace BlackCore
Q_UNUSED(c);
}
QList<CAircraftSituationList> IInterpolator::getSituationsTimeSplit(const CCallsign &callsign, qint64 splitTimeMsSinceEpoch) const
CAircraftSituationList IInterpolator::getInterpolatedSituations(qint64 currentTimeMsSinceEpoch)
{
QReadLocker l(&m_situationsLock);
static const QList<CAircraftSituationList> empty({ CAircraftSituationList(), CAircraftSituationList() });
if (!this->m_situationsByCallsign.contains(callsign)) { return empty; }
return this->m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch);
}
bool IInterpolator::hasEnoughAircraftSituations(const CCallsign &callsign) const
{
QReadLocker l(&m_situationsLock);
if (!this->m_situationsByCallsign.contains(callsign)) { return false; }
return this->m_situationsByCallsign[callsign].findBeforeNowMinusOffset(TimeOffsetMs).size() > 0;
}
CAircraftParts IInterpolator::getLatestPartsBeforeOffset(const CCallsign &callsign, qint64 timeOffset, bool *ok) const
{
QReadLocker l(&m_partsLock);
static const CAircraftParts empty;
if (ok) { *ok = false; }
if (this->m_partsByCallsign.contains(callsign)) { return empty; }
CAircraftPartsList partsList = this->m_partsByCallsign[callsign].findBeforeNowMinusOffset(timeOffset);
l.unlock();
if (partsList.isEmpty()) { return empty; }
if (ok) { *ok = true; }
return partsList.latestValue();
}
void IInterpolator::syncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch)
{
QReadLocker l(&m_situationsLock);
Q_ASSERT(requestId >= 0);
const QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> situationsCopy(m_situationsByCallsign);
QReadLocker l(&m_lockSituations);
const CSituationsPerCallsign situationsCopy(m_situationsByCallsign);
l.unlock();
CAircraftSituationList latestInterpolations;
if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); }
for (const CCallsign &cs : situationsCopy.keys())
{
bool ok = false;
CAircraftSituation situation = getCurrentInterpolatedSituation(situationsCopy, cs, currentTimeMsSinceEpoch, &ok);
if (ok)
InterpolationStatus status;
CAircraftSituation situation = getInterpolatedSituation(cs, currentTimeMsSinceEpoch, status, &situationsCopy);
if (status.allTrue())
{
latestInterpolations.push_back(situation);
}
@@ -86,71 +57,51 @@ namespace BlackCore
// further logging could go here
}
}
QWriteLocker wl(&m_requestedInterpolationsLock);
while (m_requestedInterpolations.size() >= MaxKeptInterpolationRequests - 1)
{
m_requestedInterpolations.erase(--m_requestedInterpolations.end());
}
m_requestedInterpolations.insert(requestId, latestInterpolations); // new to old
if (m_withDebugMsg)
{
CLogMessage(this).debug() << "Added request" << requestId << "with" << latestInterpolations.size() << "interpolation(s)";
}
return latestInterpolations;
}
void IInterpolator::asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch)
IInterpolator::CSituationsPerCallsign IInterpolator::getSituationsByCallsign() const
{
Q_ASSERT(requestId >= 0);
QMetaObject::invokeMethod(this, "syncRequestSituationsCalculationsForAllCallsigns",
Qt::QueuedConnection, Q_ARG(int, requestId), Q_ARG(qint64, currentTimeMsSinceEpoch));
}
QHash<CCallsign, CAircraftSituationList> IInterpolator::getSituationsByCallsign() const
{
QReadLocker l(&m_situationsLock);
QReadLocker l(&m_lockSituations);
return m_situationsByCallsign;
}
CAircraftPartsList IInterpolator::getAndRemovePartsBeforeOffset(const CCallsign &callsign, qint64 cutoffTime, BlackCore::IInterpolator::PartsStatus &partsStatus)
{
static const CAircraftPartsList empty;
partsStatus.reset();
QWriteLocker l(&m_lockParts);
if (this->m_partsByCallsign.contains(callsign))
{
partsStatus.supportsParts = true;
return this->m_partsByCallsign[callsign].findBeforeAndRemove(cutoffTime);
}
else
{
partsStatus.supportsParts = m_aircraftSupportingParts.contains(callsign);
return empty;
}
}
void IInterpolator::clear()
{
QWriteLocker s(&m_lockSituations);
QWriteLocker p(&m_lockParts);
m_situationsByCallsign.clear();
m_partsByCallsign.clear();
}
CAircraftSituationList IInterpolator::getSituationsForCallsign(const CCallsign &callsign) const
{
QReadLocker l(&m_situationsLock);
QReadLocker l(&m_lockSituations);
static const CAircraftSituationList empty;
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
return m_situationsByCallsign[callsign];
}
int IInterpolator::latestFinishedRequestId() const
{
QReadLocker l(&m_requestedInterpolationsLock);
if (m_requestedInterpolations.isEmpty()) { return -1; }
return m_requestedInterpolations.keys().first();
}
CAircraftSituationList IInterpolator::latestFinishedRequest() const
{
QReadLocker l(&m_requestedInterpolationsLock);
static const CAircraftSituationList empty;
if (m_requestedInterpolations.isEmpty()) { return empty; }
return m_requestedInterpolations.values().first();
}
CAircraftSituationList IInterpolator::getRequest(int requestId, bool *ok) const
{
QReadLocker l(&m_requestedInterpolationsLock);
static const CAircraftSituationList empty;
if (!m_requestedInterpolations.contains(requestId))
{
if (ok) { *ok = false; }
return empty;
}
if (ok) { *ok = true; }
return m_requestedInterpolations[requestId];
}
void IInterpolator::ps_onAddedAircraftSituation(const CAircraftSituation &situation)
{
QWriteLocker lock(&m_situationsLock);
QWriteLocker lock(&m_lockSituations);
const CCallsign callsign(situation.getCallsign());
Q_ASSERT(!callsign.isEmpty());
if (callsign.isEmpty()) { return; }
@@ -158,32 +109,57 @@ namespace BlackCore
// list from new to old
CAircraftSituationList &l = this->m_situationsByCallsign[callsign];
l.insertTimestampObject(situation, MaxSituationsPerCallsign);
l.push_frontMaxElements(situation, MaxSituationsPerCallsign);
}
void IInterpolator::ps_onAddedAircraftParts(const CAircraftParts &parts)
{
QWriteLocker lock(&m_partsLock);
QWriteLocker lock(&m_lockParts);
const CCallsign callsign(parts.getCallsign());
Q_ASSERT(!callsign.isEmpty());
if (callsign.isEmpty()) { return; }
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << parts.getCallsign() << parts.getMSecsSinceEpoch(); }
// list from new to old
// list sorted from new to old
CAircraftPartsList &l = this->m_partsByCallsign[callsign];
l.insertTimestampObject(parts, MaxPartsPerCallsign);
l.push_frontMaxElements(parts, MaxPartsPerCallsign);
if (m_aircraftSupportingParts.contains(callsign)) { return; }
m_aircraftSupportingParts.push_back(callsign);
}
void IInterpolator::ps_onRemovedAircraft(const CCallsign &callsign)
{
QWriteLocker ls(&m_situationsLock);
QWriteLocker lp(&m_partsLock);
QWriteLocker ls(&m_lockSituations);
QWriteLocker lp(&m_lockParts);
Q_ASSERT(!callsign.isEmpty());
if (callsign.isEmpty()) { return; }
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << callsign; }
this->m_partsByCallsign.remove(callsign);
this->m_situationsByCallsign.remove(callsign);
this->m_aircraftSupportingParts.remove(callsign);
}
bool IInterpolator::InterpolationStatus::allTrue() const
{
return interpolationSucceeded && changedPosition;
}
void IInterpolator::InterpolationStatus::reset()
{
changedPosition = false;
interpolationSucceeded = false;
}
bool IInterpolator::PartsStatus::allTrue() const
{
return supportsParts;
}
void IInterpolator::PartsStatus::reset()
{
supportsParts = false;
}
} // namespace

View File

@@ -29,45 +29,72 @@ namespace BlackCore
Q_OBJECT
public:
//! Situations per callsign
typedef QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> CSituationsPerCallsign;
//! Parts per callsign
typedef QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftPartsList> CPartsPerCallsign;
//! Virtual destructor
virtual ~IInterpolator() {}
//! Log category
static QString getMessageCategory() { return "swift.iinterpolator"; }
//! Has situations?
//! \deprecated Try not to use, it would be more efficient to directly getting the values and decide then
//! \threadsafe
virtual bool hasEnoughAircraftSituations(const BlackMisc::Aviation::CCallsign &callsign) const;
//! Status of interpolation
struct InterpolationStatus
{
public:
bool changedPosition = false; //!< position was changed
bool interpolationSucceeded = false; //!< interpolation succeeded (means enough values, etc.)
//! all OK
bool allTrue() const;
//! Reset to default values
void reset();
};
//! Status regarding parts
struct PartsStatus
{
bool supportsParts = false; //!< supports parts for given callsign
//! all OK
bool allTrue() const;
//! Reset to default values
void reset();
};
//! Current interpolated situation
//! \threadsafe
virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> &allSituations, const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc = -1, bool *ok = nullptr) const = 0;
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc,
InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign = nullptr) const = 0;
//! Latest parts before time - offset
//! Do a complete calculation for all know callsigns.
//! \param currentTimeMsSinceEpoch if no value is passed current time is used
//! \threadsafe
BlackMisc::Aviation::CAircraftParts getLatestPartsBeforeOffset(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset = TimeOffsetMs, bool *ok = nullptr) const;
//!
virtual BlackMisc::Aviation::CAircraftSituationList getInterpolatedSituations(qint64 currentTimeMsSinceEpoch = -1);
//! The situations per callsign
//! \threadsafe
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> getSituationsByCallsign() const;
CSituationsPerCallsign getSituationsByCallsign() const;
//! Parts before given offset time (aka pending parts)
//! \threadsafe
virtual BlackMisc::Aviation::CAircraftPartsList getAndRemovePartsBeforeOffset(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset, PartsStatus &partsStatus);
//! Clear all data
//! \threadsafe
virtual void clear();
//! Situations for given callsign
//! \threadsafe
BlackMisc::Aviation::CAircraftSituationList getSituationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const;
//! Last finished request id, -1 means none
//! \threadsafe
int latestFinishedRequestId() const;
//! Latest calculation
//! \threadsafe
BlackMisc::Aviation::CAircraftSituationList latestFinishedRequest() const;
//! Calculation by id
//! \threadsafe
BlackMisc::Aviation::CAircraftSituationList getRequest(int requestId, bool *ok = nullptr) const;
//! Enable debug messages
void enableDebugMessages(bool enabled);
@@ -76,20 +103,6 @@ namespace BlackCore
static const int MaxPartsPerCallsign = 3; //!< How many parts per callsign
static const int MaxKeptInterpolationRequests = 3; //!< How many requests are stored
public slots:
//! Do a complete calculation for all know callsigns in background.
//! Only use positive numbers.
//! \param requestId
//! \param currentTimeMsSinceEpoch if no value is passed current time is used
//! \threadsafe
//!
void syncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch = -1);
//! Do a complete calculation for all know callsigns in background.
//! Non blocking call of \sa syncRequestSituationsCalculationsForAllCallsigns
//! \threadsafe
void asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch = -1);
private slots:
//! New situation got added
//! \threadsafe
@@ -107,23 +120,17 @@ namespace BlackCore
//! Constructor
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProviderReadOnly *provider, const QString &workerName, QObject *parent = nullptr);
//! Situations for times before / after
//! \sa ITimestampObjectList::splitByTime
//! \threadsafe
//! \deprecated For first version
QList<BlackMisc::Aviation::CAircraftSituationList> getSituationsTimeSplit(const BlackMisc::Aviation::CCallsign &callsign, qint64 splitTimeMsSinceEpoch) const;
bool m_withDebugMsg = false; //!< allows to disable debug messages
private:
mutable QReadWriteLock m_situationsLock;
mutable QReadWriteLock m_partsLock;
mutable QReadWriteLock m_requestedInterpolationsLock;
BlackMisc::Aviation::CCallsignList m_aircraftSupportingParts; //!< aircraft supporting parts
// hashs, because not sorted by key but keeping order
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> m_situationsByCallsign;
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftPartsList> m_partsByCallsign;
QHash<int, BlackMisc::Aviation::CAircraftSituationList> m_requestedInterpolations;
CSituationsPerCallsign m_situationsByCallsign; //!< situations
CPartsPerCallsign m_partsByCallsign; //!< parts
// locks
mutable QReadWriteLock m_lockSituations; //!< lock for situations
mutable QReadWriteLock m_lockParts; //!< lock for parts
};
} // namespace

View File

@@ -20,18 +20,31 @@ using namespace BlackMisc::Aviation;
namespace BlackCore
{
CAircraftSituation CInterpolatorLinear::getCurrentInterpolatedSituation(const QHash<CCallsign, CAircraftSituationList> &allSituations, const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, bool *ok) const
CAircraftSituation CInterpolatorLinear::getInterpolatedSituation(const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign) const
{
const static CAircraftSituation empty;
if (ok) { *ok = false; }
if (!allSituations.contains(callsign)) { return empty; }
if (allSituations[callsign].isEmpty()) { return empty; }
status.reset();
QList<CAircraftSituationList> splitSituations;
if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); }
qint64 splitTimeMsSinceEpoch = currentTimeMsSinceEpoc - TimeOffsetMs;
QList<CAircraftSituationList> splitSituations = allSituations[callsign].splitByTime(splitTimeMsSinceEpoch);
CAircraftSituationList &situationsNewer = splitSituations[0]; // latest first
CAircraftSituationList &situationsOlder = splitSituations[1]; // latest first
if (situationsPerCallsign)
{
if (!situationsPerCallsign->contains(callsign)) { return empty; }
if ((*situationsPerCallsign)[callsign].isEmpty()) { return empty; }
splitSituations = (*situationsPerCallsign)[callsign].splitByTime(splitTimeMsSinceEpoch);
}
else
{
// only part where it is locked
QReadLocker lock(&m_lockSituations);
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
if (m_situationsByCallsign[callsign].isEmpty()) { return empty; }
splitSituations = m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch);
}
CAircraftSituationList &situationsNewer = splitSituations[0]; // newer part
CAircraftSituationList &situationsOlder = splitSituations[1]; // older part
// interpolation situations
CAircraftSituation oldSituation;
@@ -52,7 +65,6 @@ namespace BlackCore
// We just place at he last position until we get before / after situations
if (situationsOlderNo < 1 || situationsNewerNo < 1)
{
if (ok) { *ok = true; }
// no after situations
if (situationsOlderNo < 1) { return situationsNewer.back(); } // oldest newest
@@ -73,6 +85,7 @@ namespace BlackCore
CAircraftSituation currentSituation(oldSituation);
CCoordinateGeodetic currentPosition;
status.interpolationSucceeded = true;
// Time between start and end packet
double deltaTime = oldSituation.absMsecsTo(newSituation);
@@ -82,7 +95,7 @@ namespace BlackCore
// 1) values > 1 mean extrapolation
// 2) values > 2 mean no new situations coming in
double simulationTimeFraction = 1 - ((newSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime);
if (simulationTimeFraction > 1.5)
if (simulationTimeFraction > 2.0)
{
if (this->m_withDebugMsg)
{
@@ -91,21 +104,34 @@ namespace BlackCore
}
// Interpolate latitude: Lat = (LatB - LatA) * t + LatA
currentPosition.setLatitude((newSituation.getPosition().latitude() - oldSituation.getPosition().latitude())
const CLatitude oldLat(oldSituation.latitude());
const CLatitude newLat(newSituation.latitude());
const CLongitude oldLng(oldSituation.longitude());
const CLongitude newLng(newSituation.longitude());
currentPosition.setLatitude((newLat - oldLat)
* simulationTimeFraction
+ oldSituation.getPosition().latitude());
+ oldLat);
// Interpolate latitude: Lon = (LonB - LonA) * t + LonA
currentPosition.setLongitude((newSituation.getPosition().longitude() - oldSituation.getPosition().longitude())
currentPosition.setLongitude((newLng - oldLng)
* simulationTimeFraction
+ oldSituation.getPosition().longitude());
+ oldLng);
currentSituation.setPosition(currentPosition);
// Interpolate altitude: Alt = (AltB - AltA) * t + AltA
currentSituation.setAltitude(CAltitude((newSituation.getAltitude() - oldSituation.getAltitude())
const CAltitude oldAlt(oldSituation.getAltitude());
const CAltitude newAlt(newSituation.getAltitude());
Q_ASSERT(oldAlt.getReferenceDatum() == newAlt.getReferenceDatum()); // otherwise no calculation is possible
currentSituation.setAltitude(CAltitude((newAlt - oldAlt)
* simulationTimeFraction
+ oldSituation.getAltitude(),
oldSituation.getAltitude().getReferenceDatum()));
+ oldAlt,
oldAlt.getReferenceDatum()));
if (newLat == oldLat && newLng == oldLng && oldAlt == newAlt)
{
return currentSituation;
}
// Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA
CHeading headingBegin = oldSituation.getHeading();
@@ -143,13 +169,13 @@ namespace BlackCore
// TODO: According to the specification, banks to the right should be negative.
// But somehow we get positive banks from the network.
bank *= -1;
bank *= -1.0;
currentSituation.setBank(bank);
currentSituation.setGroundspeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed())
* simulationTimeFraction
+ oldSituation.getGroundSpeed());
if (ok) { *ok = true; }
status.changedPosition = true;
Q_ASSERT(currentSituation.getCallsign() == callsign);
return currentSituation;
}

View File

@@ -30,7 +30,7 @@ namespace BlackCore
{}
//! \copydoc IInterpolator::getCurrentInterpolatedSituation
virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> &allSituations, const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc = -1, bool *ok = nullptr) const override;
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc, InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign = nullptr) const override;
//! Log category
static QString getMessageCategory() { return "swift.interpolatorlinear"; }

View File

@@ -430,8 +430,9 @@ namespace BlackCore
/*!
* We received a notification of the state of another aircraft on the network.
* Corresponding callsign in \sa CAircraftSituation::getCallsign .
*/
void aircraftPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation,
void aircraftPositionUpdate(const BlackMisc::Aviation::CAircraftSituation &situation,
const BlackMisc::Aviation::CTransponder &transponder);
/*!

View File

@@ -648,16 +648,17 @@ namespace BlackCore
{
const CCallsign callsign(callsignChar);
const CAircraftSituation situation(
callsign,
CCoordinateGeodetic(position->latitude, position->longitude, 0.0),
CAltitude(position->altitudeTrue, CAltitude::AboveGround, CLengthUnit::ft()),
CAltitude(position->altitudeTrue, CAltitude::MeanSeaLevel, CLengthUnit::ft()),
CHeading(position->heading, CHeading::True, CAngleUnit::deg()),
CAngle(position->pitch, CAngleUnit::deg()),
CAngle(position->bank, CAngleUnit::deg()),
CSpeed(position->groundSpeed, CSpeedUnit::kts())
);
QString tn("transponder ");
tn.append(callsign.asString());
QString transponderName("transponder ");
transponderName.append(callsign.asString());
CTransponder::TransponderMode mode = CTransponder::StateStandby;
switch (position->transponderMode)
{
@@ -675,19 +676,21 @@ namespace BlackCore
break;
}
// I did have a situation where I got wrong transponger codes (KB)
// I did have a situation where I got wrong transponder codes (KB)
// So I now check for a valid code in order to detect such codes
CTransponder transponder(tn, 0, mode);
CTransponder transponder;
if (CTransponder::isValidTransponderCode(position->transponderCode))
{
transponder = CTransponder(tn, position->transponderCode, mode);
transponder = CTransponder(transponderName, position->transponderCode, mode);
}
else
{
// TODO: how do with log this
qDebug() << "Wrong transponder code" << position->transponderMode << callsign;
CLogMessage(static_cast<CNetworkVatlib *>(nullptr)).warning("Wrong transponder code %1 for %2") << position->transponderCode << callsign;
// default
transponder = CTransponder(transponderName, 7000, mode);
}
emit cbvar_cast(cbvar)->aircraftPositionUpdate(callsign, situation, transponder);
emit cbvar_cast(cbvar)->aircraftPositionUpdate(situation, transponder);
}
void CNetworkVatlib::onAircraftConfigReceived(VatSessionID, const char *callsign, const char *aircraftConfig, void *cbvar)

View File

@@ -27,7 +27,9 @@ namespace BlackCore
/*!
* Implementation of INetwork using the vatlib shim
*/
class CNetworkVatlib : public INetwork, public BlackMisc::Simulation::COwnAircraftProviderSupport
class CNetworkVatlib :
public INetwork,
public BlackMisc::Simulation::COwnAircraftProviderSupport // network vatlib consumes own aircraft data and sets ICAO/callsign data
{
Q_OBJECT