refs #395, post merge and rebase adjustments plus further testing fixes:

* adjusted iterim position updates
* removed deadlocks (thread safe values in airspace monitor)
* resolved some merge issues
* some smaller fixes in airspace monitor (style, finders)
This commit is contained in:
Klaus Basan
2015-04-25 01:36:24 +02:00
committed by Mathew Sutcliffe
parent 6debd33b4f
commit 085edc82cb
5 changed files with 115 additions and 121 deletions

View File

@@ -32,6 +32,9 @@ namespace BlackCore
m_network(network), m_vatsimBookingReader(bookings), m_vatsimDataFileReader(dataFile), m_network(network), m_vatsimBookingReader(bookings), m_vatsimDataFileReader(dataFile),
m_analyzer(new CAirspaceAnalyzer(ownAircraftProvider, this, network, this)) m_analyzer(new CAirspaceAnalyzer(ownAircraftProvider, this, network, this))
{ {
this->setObjectName("CAirspaceMonitor");
m_interimPositionUpdateTimer.setObjectName(this->objectName().append(":m_interimPositionUpdateTimer"));
this->connect(this->m_network, &INetwork::atcPositionUpdate, this, &CAirspaceMonitor::ps_atcPositionUpdate); this->connect(this->m_network, &INetwork::atcPositionUpdate, this, &CAirspaceMonitor::ps_atcPositionUpdate);
this->connect(this->m_network, &INetwork::atisReplyReceived, this, &CAirspaceMonitor::ps_atisReceived); this->connect(this->m_network, &INetwork::atisReplyReceived, this, &CAirspaceMonitor::ps_atisReceived);
this->connect(this->m_network, &INetwork::atisVoiceRoomReplyReceived, this, &CAirspaceMonitor::ps_atisVoiceRoomReceived); this->connect(this->m_network, &INetwork::atisVoiceRoomReplyReceived, this, &CAirspaceMonitor::ps_atisVoiceRoomReceived);
@@ -49,7 +52,7 @@ namespace BlackCore
this->connect(this->m_network, &INetwork::customFSinnPacketReceived, this, &CAirspaceMonitor::ps_customFSinnPacketReceived); this->connect(this->m_network, &INetwork::customFSinnPacketReceived, this, &CAirspaceMonitor::ps_customFSinnPacketReceived);
this->connect(this->m_network, &INetwork::serverReplyReceived, this, &CAirspaceMonitor::ps_serverReplyReceived); this->connect(this->m_network, &INetwork::serverReplyReceived, this, &CAirspaceMonitor::ps_serverReplyReceived);
this->connect(this->m_network, &INetwork::aircraftConfigPacketReceived, this, &CAirspaceMonitor::ps_aircraftConfigReceived); this->connect(this->m_network, &INetwork::aircraftConfigPacketReceived, this, &CAirspaceMonitor::ps_aircraftConfigReceived);
this->connect(&m_interimPositionUpdateTimer, &QTimer::timeout, this, &CAirspaceMonitor::ps_sendInterimPosition); this->connect(&m_interimPositionUpdateTimer, &QTimer::timeout, this, &CAirspaceMonitor::ps_sendInterimPositions);
// AutoConnection: this should also avoid race conditions by updating the bookings // AutoConnection: this should also avoid race conditions by updating the bookings
this->connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CAirspaceMonitor::ps_receivedBookings); this->connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CAirspaceMonitor::ps_receivedBookings);
@@ -228,10 +231,11 @@ namespace BlackCore
CCallsignSet searchList(callsigns); CCallsignSet searchList(callsigns);
// myself, which is not in the lists below // myself, which is not in the lists below
if (!ownAircraft().getCallsign().isEmpty() && searchList.contains(ownAircraft().getCallsign())) CSimulatedAircraft myAircraft(ownAircraft());
if (!myAircraft.getCallsign().isEmpty() && searchList.contains(myAircraft.getCallsign()))
{ {
searchList.remove(ownAircraft().getCallsign()); searchList.remove(myAircraft.getCallsign());
users.push_back(ownAircraft().getPilot()); users.push_back(myAircraft.getPilot());
} }
// do aircraft first, this will handle most callsigns // do aircraft first, this will handle most callsigns
@@ -247,7 +251,7 @@ namespace BlackCore
} }
} }
foreach(CAtcStation station, this->m_atcStationsOnline) for (const CAtcStation &station : this->m_atcStationsOnline)
{ {
if (searchList.isEmpty()) break; if (searchList.isEmpty()) break;
CCallsign callsign = station.getCallsign(); CCallsign callsign = station.getCallsign();
@@ -260,8 +264,8 @@ namespace BlackCore
} }
// we might have unresolved callsigns // we might have unresolved callsigns
// these are the ones not in range // those are the ones not in range
foreach(CCallsign callsign, searchList) for (const CCallsign &callsign : searchList)
{ {
CUserList usersByCallsign = this->m_vatsimDataFileReader->getUsersForCallsign(callsign); CUserList usersByCallsign = this->m_vatsimDataFileReader->getUsersForCallsign(callsign);
if (usersByCallsign.isEmpty()) if (usersByCallsign.isEmpty())
@@ -281,11 +285,8 @@ namespace BlackCore
CClientList CAirspaceMonitor::getOtherClientsForCallsigns(const CCallsignSet &callsigns) const CClientList CAirspaceMonitor::getOtherClientsForCallsigns(const CCallsignSet &callsigns) const
{ {
CClientList clients; CClientList clients;
if (callsigns.isEmpty()) return clients; if (callsigns.isEmpty()) { return clients; }
for (const CCallsign &callsign : callsigns) clients.push_back(this->m_otherClients.findByCallsigns(callsigns));
{
clients.push_back(this->m_otherClients.findBy(&CClient::getCallsign, callsign));
}
return clients; return clients;
} }
@@ -325,18 +326,14 @@ namespace BlackCore
{ {
CAtcStation station; CAtcStation station;
CAtcStationList stations = this->m_atcStationsOnline.findIfComUnitTunedIn25KHz(comSystem); CAtcStationList stations = this->m_atcStationsOnline.findIfComUnitTunedIn25KHz(comSystem);
if (!stations.isEmpty()) if (stations.isEmpty()) { return station; }
{ stations.sortByDistanceToOwnAircraft();
stations.sortBy(&CAtcStation::getDistanceToOwnAircraft); return stations.front();
station = stations.front();
}
return station;
} }
void CAirspaceMonitor::requestDataUpdates() void CAirspaceMonitor::requestDataUpdates()
{ {
if (!this->m_network->isConnected()) return; if (!this->m_network->isConnected()) { return; }
for (const CAircraft &aircraft : this->getAircraftInRange()) for (const CAircraft &aircraft : this->getAircraftInRange())
{ {
const CCallsign cs(aircraft.getCallsign()); const CCallsign cs(aircraft.getCallsign());
@@ -428,7 +425,7 @@ namespace BlackCore
// Client // Client
vm = CPropertyIndexVariantMap({CClient::IndexUser, CUser::IndexRealName}, realname); vm = CPropertyIndexVariantMap({CClient::IndexUser, CUser::IndexRealName}, realname);
vm.addValue({ CClient::IndexVoiceCapabilities }, caps); vm.addValue({ CClient::IndexVoiceCapabilities }, caps);
if (!this->m_otherClients.contains(&CClient::getCallsign, callsign)) { this->m_otherClients.push_back(CClient(callsign)); } if (!this->m_otherClients.containsCallsign(callsign)) { this->m_otherClients.push_back(CClient(callsign)); }
this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm); this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm);
} }
@@ -444,7 +441,7 @@ namespace BlackCore
CPropertyIndexVariantMap vm(CClient::IndexCapabilities, capabilities.toCVariant()); CPropertyIndexVariantMap vm(CClient::IndexCapabilities, capabilities.toCVariant());
CVoiceCapabilities caps = m_vatsimDataFileReader->getVoiceCapabilityForCallsign(callsign); CVoiceCapabilities caps = m_vatsimDataFileReader->getVoiceCapabilityForCallsign(callsign);
vm.addValue({CClient::IndexVoiceCapabilities}, caps); vm.addValue({CClient::IndexVoiceCapabilities}, caps);
if (!this->m_otherClients.contains(&CClient::getCallsign, callsign)) { this->m_otherClients.push_back(CClient(callsign)); } if (!this->m_otherClients.containsCallsign(callsign)) { this->m_otherClients.push_back(CClient(callsign)); }
this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm); this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm);
// apply same to client in aircraft // apply same to client in aircraft
@@ -464,7 +461,7 @@ namespace BlackCore
// Request of other client, I can get the other's model from that // Request of other client, I can get the other's model from that
CPropertyIndexVariantMap vm({ CClient::IndexModel, CAircraftModel::IndexModelString }, model); CPropertyIndexVariantMap vm({ CClient::IndexModel, CAircraftModel::IndexModelString }, model);
vm.addValue({ CClient::IndexModel, CAircraftModel::IndexModelType }, static_cast<int>(CAircraftModel::TypeQueriedFromNetwork)); vm.addValue({ CClient::IndexModel, CAircraftModel::IndexModelType }, static_cast<int>(CAircraftModel::TypeQueriedFromNetwork));
if (!this->m_otherClients.contains(&CClient::getCallsign, callsign)) if (!this->m_otherClients.containsCallsign(callsign))
{ {
// with custom packets it can happen, // with custom packets it can happen,
// the packet is received before any other packet // the packet is received before any other packet
@@ -482,7 +479,6 @@ namespace BlackCore
// if update was successful we know we have that callsign, otherwise explicit check // if update was successful we know we have that callsign, otherwise explicit check
aircraftContainsCallsign = (u > 0) || this->m_aircraftInRange.containsCallsign(callsign); aircraftContainsCallsign = (u > 0) || this->m_aircraftInRange.containsCallsign(callsign);
} }
this->sendFsipiCustomPacket(callsign); // response
// ICAO response from custom data // ICAO response from custom data
if (!aircraftDesignator.isEmpty()) if (!aircraftDesignator.isEmpty())
@@ -504,7 +500,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_serverReplyReceived(const CCallsign &callsign, const QString &server) void CAirspaceMonitor::ps_serverReplyReceived(const CCallsign &callsign, const QString &server)
{ {
if (!this->m_connected || callsign.isEmpty() || server.isEmpty()) { return; } if (!this->m_connected || callsign.isEmpty() || server.isEmpty()) { return; }
if (!this->m_otherClients.contains(&CClient::getCallsign, callsign)) { this->m_otherClients.push_back(CClient(callsign)); } if (!this->m_otherClients.containsCallsign(callsign)) { this->m_otherClients.push_back(CClient(callsign)); }
CPropertyIndexVariantMap vm(CClient::IndexServer, server); CPropertyIndexVariantMap vm(CClient::IndexServer, server);
this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm); this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm);
} }
@@ -522,8 +518,8 @@ namespace BlackCore
this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsignTower, vm); this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsignTower, vm);
this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsignTower, vm); this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsignTower, vm);
this->m_metarCache.insert(icaoCode, metar); this->m_metarCache.insert(icaoCode, metar);
if (this->m_atcStationsOnline.contains(&CAtcStation::getCallsign, callsignTower)) { emit this->changedAtcStationsOnline(); } if (this->m_atcStationsOnline.containsCallsign(callsignTower)) { emit this->changedAtcStationsOnline(); }
if (this->m_atcStationsBooked.contains(&CAtcStation::getCallsign, callsignTower)) { emit this->changedAtcStationsBooked(); } if (this->m_atcStationsBooked.containsCallsign(callsignTower)) { emit this->changedAtcStationsBooked(); }
} }
void CAirspaceMonitor::ps_flightPlanReceived(const CCallsign &callsign, const CFlightPlan &flightPlan) void CAirspaceMonitor::ps_flightPlanReceived(const CCallsign &callsign, const CFlightPlan &flightPlan)
@@ -540,16 +536,14 @@ namespace BlackCore
void CAirspaceMonitor::removeAllAircraft() void CAirspaceMonitor::removeAllAircraft()
{ {
QWriteLocker l1(&m_lockParts); for (const CAircraft &aircraft : getAircraftInRange())
QWriteLocker l2(&m_lockSituations);
QWriteLocker l3(&m_lockAircraft);
for (const CAircraft &aircraft : m_aircraftInRange)
{ {
const CCallsign cs(aircraft.getCallsign()); const CCallsign cs(aircraft.getCallsign());
emit removedAircraft(cs); emit removedAircraft(cs);
} }
QWriteLocker l1(&m_lockParts);
QWriteLocker l2(&m_lockSituations);
m_situationsByCallsign.clear(); m_situationsByCallsign.clear();
m_partsByCallsign.clear(); m_partsByCallsign.clear();
m_aircraftSupportingParts.clear(); m_aircraftSupportingParts.clear();
@@ -601,21 +595,18 @@ namespace BlackCore
void CAirspaceMonitor::ps_receivedDataFile() void CAirspaceMonitor::ps_receivedDataFile()
{ {
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
for (auto i = this->m_otherClients.begin(); i != this->m_otherClients.end(); ++i) for (auto client = this->m_otherClients.begin(); client != this->m_otherClients.end(); ++client)
{ {
CClient client = (*i); if (client->hasSpecifiedVoiceCapabilities()) { continue; } // we already have voice caps
if (client.hasSpecifiedVoiceCapabilities()) continue; CVoiceCapabilities vc = this->m_vatsimDataFileReader->getVoiceCapabilityForCallsign(client->getCallsign());
CVoiceCapabilities vc = this->m_vatsimDataFileReader->getVoiceCapabilityForCallsign(client.getCallsign()); if (vc.isUnknown()) { continue; }
if (vc.isUnknown()) continue; client->setVoiceCapabilities(vc);
client.setVoiceCapabilities(vc);
(*i) = client;
} }
} }
void CAirspaceMonitor::ps_sendReadyForModelMatching(const CCallsign &callsign, int trial) void CAirspaceMonitor::ps_sendReadyForModelMatching(const CCallsign &callsign, int trial)
{ {
// some checks for special conditions, e.g. logout -> empty list, but still signals pending // some checks for special conditions, e.g. logout -> empty list, but still signals pending
// lock block
CSimulatedAircraft remoteAircraft; CSimulatedAircraft remoteAircraft;
{ {
QReadLocker l(&m_lockAircraft); QReadLocker l(&m_lockAircraft);
@@ -704,7 +695,7 @@ namespace BlackCore
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
this->m_otherClients.removeByCallsign(callsign); this->m_otherClients.removeByCallsign(callsign);
if (this->m_atcStationsOnline.contains(&CAtcStation::getCallsign, callsign)) if (this->m_atcStationsOnline.containsCallsign(callsign))
{ {
CAtcStation removedStation = this->m_atcStationsOnline.findFirstByCallsign(callsign); CAtcStation removedStation = this->m_atcStationsOnline.findFirstByCallsign(callsign);
this->m_atcStationsOnline.removeByCallsign(callsign); this->m_atcStationsOnline.removeByCallsign(callsign);
@@ -799,6 +790,7 @@ namespace BlackCore
} }
// ICAO code received when aircraft is already removed or not yet ready // ICAO code received when aircraft is already removed or not yet ready
// We add it to cache and use it when aircraft is created // We add it to cache and use it when aircraft is created
int c;
{ {
QWriteLocker l(&m_lockAircraft); QWriteLocker l(&m_lockAircraft);
if (!this->m_aircraftInRange.containsCallsign(callsign)) if (!this->m_aircraftInRange.containsCallsign(callsign))
@@ -808,18 +800,18 @@ namespace BlackCore
} }
// update // update
int c = this->m_aircraftInRange.applyIfCallsign(callsign, vm); c = this->m_aircraftInRange.applyIfCallsign(callsign, vm);
if (c > 0) { ps_sendReadyForModelMatching(callsign, 1); }
} }
if (c > 0) { ps_sendReadyForModelMatching(callsign, 1); }
} }
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder) void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder)
{ {
Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), "ps_aircraftUpdateReceived", "Called in different thread"); Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "Called in different thread");
if (!this->m_connected) { return; } if (!this->m_connected) { return; }
CCallsign callsign(situation.getCallsign()); CCallsign callsign(situation.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), "ps_aircraftUpdateReceived", "Empty callsign"); Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Empty callsign");
// store situation history // store situation history
this->storeAircraftSituation(situation); this->storeAircraftSituation(situation);
@@ -852,7 +844,7 @@ namespace BlackCore
this->m_aircraftInRange.push_back(aircraft); this->m_aircraftInRange.push_back(aircraft);
// new client, there is a chance it has been already created by custom packet // new client, there is a chance it has been already created by custom packet
if (!this->m_otherClients.contains(&CClient::getCallsign, callsign)) if (!this->m_otherClients.containsCallsign(callsign))
{ {
CClient c(callsign); CClient c(callsign);
this->m_otherClients.push_back(c); // initial, will be filled by data later this->m_otherClients.push_back(c); // initial, will be filled by data later
@@ -905,38 +897,41 @@ namespace BlackCore
void CAirspaceMonitor::ps_aircraftInterimUpdateReceived(const CAircraftSituation &situation) void CAirspaceMonitor::ps_aircraftInterimUpdateReceived(const CAircraftSituation &situation)
{ {
Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), "ps_aircraftInterimUpdateReceived", "Called in different thread"); Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "Called in different thread");
if (!this->m_connected) { return; } if (!this->m_connected) { return; }
CCallsign callsign(situation.getCallsign()); CCallsign callsign(situation.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), "ps_aircraftInterimUpdateReceived", "Empty callsign"); Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Empty callsign");
// todo: Check if the timestamp is copied here as well. // todo: Check if the timestamp is copied here as well.
CAircraftSituation sitationCopy(situation);
// Interim packets do not have groundspeed, hence set the last known value. // Interim packets do not have groundspeed, hence set the last known value.
// If there is no full position available yet, throw this interim position away. // If there is no full position available yet, throw this interim position away.
auto history = this->m_aircraftSituations.findByCallsign(callsign); CAircraftSituation iterimSituation(situation);
if (history.empty()) return; {
sitationCopy.setGroundspeed(history.latestValue().getGroundSpeed()); QReadLocker l(&m_lockSituations);
auto history = this->m_situationsByCallsign[callsign];
if (history.empty()) { return; } // we need one full situation
iterimSituation.setCurrentUtcTime();
iterimSituation.setGroundspeed(history.latestValue().getGroundSpeed());
}
// store situation history // store situation history
this->m_aircraftSituations.push_front(situation); this->storeAircraftSituation(iterimSituation);
this->m_aircraftSituations.removeOlderThanNowMinusOffset(AircraftSituationsRemovedOffsetMs); emit this->addedAircraftSituation(iterimSituation);
emit this->addedRemoteAircraftSituation(situation);
// update // update aircraft
CLength distance = ownAircraft().calculateGreatCircleDistance(situation.getPosition()); //! \todo skip aircraft updates for interim positions as for performance reasons
distance.switchUnit(CLengthUnit::NM()); CLength distance = ownAircraft().calculateGreatCircleDistance(iterimSituation.getPosition());
distance.switchUnit(CLengthUnit::NM()); // lloks nicer
CPropertyIndexVariantMap vm; CPropertyIndexVariantMap vm;
vm.addValue(CAircraft::IndexSituation, situation); vm.addValue(CAircraft::IndexSituation, iterimSituation);
vm.addValue(CAircraft::IndexDistanceToOwnAircraft, distance); vm.addValue(CAircraft::IndexDistanceToOwnAircraft, distance);
// here I expect always a changed value // here I expect always a changed value
this->m_aircraftInRange.applyIfCallsign(callsign, vm);
this->m_aircraftWatchdog.resetCallsign(callsign);
emit this->changedAircraftInRange(); emit this->changedAircraftInRange();
QWriteLocker l(&m_lockAircraft);
this->m_aircraftInRange.applyIfCallsign(callsign, vm);
} }
void CAirspaceMonitor::ps_pilotDisconnected(const CCallsign &callsign) void CAirspaceMonitor::ps_pilotDisconnected(const CCallsign &callsign)
@@ -956,13 +951,14 @@ namespace BlackCore
m_aircraftSupportingParts.remove(callsign); m_aircraftSupportingParts.remove(callsign);
} }
QWriteLocker l(&m_lockAircraft); bool containsCallsign;
bool contains = this->m_aircraftInRange.containsCallsign(callsign);
if (contains)
{ {
this->m_aircraftInRange.removeByCallsign(callsign); QWriteLocker l(&m_lockAircraft);
emit this->removedAircraft(callsign); containsCallsign = this->m_aircraftInRange.containsCallsign(callsign);
if (containsCallsign) { this->m_aircraftInRange.removeByCallsign(callsign); }
} }
if (containsCallsign) { emit this->removedAircraft(callsign); }
} }
void CAirspaceMonitor::ps_frequencyReceived(const CCallsign &callsign, const CFrequency &frequency) void CAirspaceMonitor::ps_frequencyReceived(const CCallsign &callsign, const CFrequency &frequency)
@@ -970,23 +966,23 @@ namespace BlackCore
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
// update // update
int changed;
CPropertyIndexVariantMap vm({CAircraft::IndexCom1System, CComSystem::IndexActiveFrequency}, frequency.toCVariant()); CPropertyIndexVariantMap vm({CAircraft::IndexCom1System, CComSystem::IndexActiveFrequency}, frequency.toCVariant());
QWriteLocker l(&m_lockAircraft); {
int changed = this->m_aircraftInRange.applyIf(&CAircraft::getCallsign, callsign, vm, true); QWriteLocker l(&m_lockAircraft);
changed = this->m_aircraftInRange.applyIf(&CAircraft::getCallsign, callsign, vm, true);
}
if (changed > 0) { emit this->changedAircraftInRange(); } if (changed > 0) { emit this->changedAircraftInRange(); }
} }
void CAirspaceMonitor::ps_aircraftConfigReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &jsonObject, bool isFull) void CAirspaceMonitor::ps_aircraftConfigReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &jsonObject, bool isFull)
{ {
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
QWriteLocker l(&m_lockAircraft); CSimulatedAircraft simAircraft(getAircraftForCallsign(callsign));
CSimulatedAircraftList list = this->m_aircraftInRange.findByCallsign(callsign);
// Skip unknown callsigns
if (list.isEmpty()) { return; }
CSimulatedAircraft simAircraft = list.front();
// If we are not yet synchronized, we throw away any incremental packet // If we are not yet synchronized, we throw away any incremental packet
if (!simAircraft.hasValidCallsign()) { return; }
if (!simAircraft.isPartsSynchronized() && !isFull) { return; } if (!simAircraft.isPartsSynchronized() && !isFull) { return; }
CAircraftParts parts; CAircraftParts parts;
@@ -1011,39 +1007,41 @@ namespace BlackCore
emit this->addedAircraftParts(parts); emit this->addedAircraftParts(parts);
// here I expect always a changed value // here I expect always a changed value
QWriteLocker l(&m_lockAircraft);
this->m_aircraftInRange.setAircraftParts(callsign, parts); this->m_aircraftInRange.setAircraftParts(callsign, parts);
} }
void CAirspaceMonitor::ps_sendInterimPosition() void CAirspaceMonitor::ps_sendInterimPositions()
{ {
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
if (!this->m_connected || !m_sendInterimPositions) { return; } if (!this->m_connected || !m_sendInterimPositions) { return; }
CSimulatedAircraftList aircrafts = m_aircraftInRange.findBy(&CSimulatedAircraft::fastPositionUpdates, true); CSimulatedAircraftList aircrafts = m_aircraftInRange.findBy(&CSimulatedAircraft::fastPositionUpdates, true);
m_network->sendInterimPosition(aircrafts.getCallsigns()); m_network->sendInterimPositions(aircrafts.getCallsigns());
}
void CAirspaceMonitor::storeAircraftSituation(const CAircraftSituation &situation) void CAirspaceMonitor::storeAircraftSituation(const CAircraftSituation &situation)
{ {
QWriteLocker lock(&m_lockSituations);
const CCallsign callsign(situation.getCallsign()); const CCallsign callsign(situation.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), "storeAircraftSituation", "empty callsign"); Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
if (callsign.isEmpty()) { return; } if (callsign.isEmpty()) { return; }
// list from new to old // list from new to old
QWriteLocker lock(&m_lockSituations);
CAircraftSituationList &l = this->m_situationsByCallsign[callsign]; CAircraftSituationList &l = this->m_situationsByCallsign[callsign];
l.push_frontMaxElements(situation, MaxSituationsPerCallsign); l.push_frontMaxElements(situation, MaxSituationsPerCallsign);
// check sort order // check sort order
Q_ASSERT_X(l.size() < 2 || l[0].getMSecsSinceEpoch() >= l[1].getMSecsSinceEpoch(), "storeAircraftSituation", "wrong sort order"); Q_ASSERT_X(l.size() < 2 || l[0].getMSecsSinceEpoch() >= l[1].getMSecsSinceEpoch(), Q_FUNC_INFO, "wrong sort order");
} }
void CAirspaceMonitor::storeAircraftParts(const CAircraftParts &parts) void CAirspaceMonitor::storeAircraftParts(const CAircraftParts &parts)
{ {
QWriteLocker lock(&m_lockParts);
const CCallsign callsign(parts.getCallsign()); const CCallsign callsign(parts.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), "storeAircraftParts", "empty callsign"); Q_ASSERT_X(!callsign.isEmpty(), "storeAircraftParts", "empty callsign");
if (callsign.isEmpty()) { return; } if (callsign.isEmpty()) { return; }
// list sorted from new to old // list sorted from new to old
QWriteLocker lock(&m_lockParts);
CAircraftPartsList &l = this->m_partsByCallsign[callsign]; CAircraftPartsList &l = this->m_partsByCallsign[callsign];
l.push_frontMaxElements(parts, MaxPartsPerCallsign); l.push_frontMaxElements(parts, MaxPartsPerCallsign);

View File

@@ -159,9 +159,6 @@ namespace BlackCore
static const qint64 AircraftPartsRemoveOffsetMs = 30 * 1000; //!< parts older than now - offset will be removed static const qint64 AircraftPartsRemoveOffsetMs = 30 * 1000; //!< parts older than now - offset will be removed
signals: signals:
//--- DBus / local signals
//! Online ATC stations were changed //! Online ATC stations were changed
void changedAtcStationsOnline(); void changedAtcStationsOnline();
@@ -218,11 +215,6 @@ namespace BlackCore
mutable QReadWriteLock m_lockParts; //!< lock for parts mutable QReadWriteLock m_lockParts; //!< lock for parts
mutable QReadWriteLock m_lockAircraft; //!< lock aircraft mutable QReadWriteLock m_lockAircraft; //!< lock aircraft
// TODO FIXME (MS) should be in INetwork
void sendFsipiCustomPacket(const BlackMisc::Aviation::CCallsign &recipientCallsign) const;
void sendFsipirCustomPacket(const BlackMisc::Aviation::CCallsign &recipientCallsign) const;
QStringList createFsipiCustomPacketData() const;
//! Remove ATC online stations //! Remove ATC online stations
void removeAllOnlineAtcStations(); void removeAllOnlineAtcStations();
@@ -274,7 +266,7 @@ namespace BlackCore
void ps_receivedDataFile(); void ps_receivedDataFile();
void ps_aircraftConfigReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &jsonObject, bool isFull); void ps_aircraftConfigReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &jsonObject, bool isFull);
void ps_aircraftInterimUpdateReceived(const BlackMisc::Aviation::CAircraftSituation &situation); void ps_aircraftInterimUpdateReceived(const BlackMisc::Aviation::CAircraftSituation &situation);
void ps_sendInterimPosition(); void ps_sendInterimPositions();
}; };
} // namespace } // namespace

View File

@@ -346,7 +346,7 @@ namespace BlackCore
* Send interim position directly to a set of receivers. * Send interim position directly to a set of receivers.
* \pre Network must be connected when calling this function. * \pre Network must be connected when calling this function.
*/ */
virtual void sendInterimPosition(const BlackMisc::Aviation::CCallsignSet &receiver) = 0; virtual void sendInterimPositions(const BlackMisc::Aviation::CCallsignSet &receiver) = 0;
//! @} //! @}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

@@ -119,14 +119,15 @@ namespace BlackCore
if (isConnected()) if (isConnected())
{ {
CSimulatedAircraft myAircraft(ownAircraft());
if (this->m_loginMode == LoginAsObserver) if (this->m_loginMode == LoginAsObserver)
{ {
// Observer // Observer
VatAtcPosition pos; VatAtcPosition pos;
pos.facility = vatFacilityTypeUnknown; pos.facility = vatFacilityTypeUnknown;
pos.visibleRange = 10; // NM pos.visibleRange = 10; // NM
pos.latitude = ownAircraft().latitude().value(CAngleUnit::deg()); pos.latitude = myAircraft.latitude().value(CAngleUnit::deg());
pos.longitude = ownAircraft().longitude().value(CAngleUnit::deg()); pos.longitude = myAircraft.longitude().value(CAngleUnit::deg());
pos.elevation = 0; pos.elevation = 0;
pos.rating = vatAtcRatingObserver; pos.rating = vatAtcRatingObserver;
pos.frequency = 199998; pos.frequency = 199998;
@@ -137,18 +138,18 @@ namespace BlackCore
// Normal / Stealth mode // Normal / Stealth mode
VatPilotPosition pos; VatPilotPosition pos;
// TODO: we need to distinguish true and pressure altitude // TODO: we need to distinguish true and pressure altitude
pos.altitudePressure = ownAircraft().getAltitude().value(CLengthUnit::ft()); pos.altitudePressure = myAircraft.getAltitude().value(CLengthUnit::ft());
pos.altitudeTrue = ownAircraft().getAltitude().value(CLengthUnit::ft()); pos.altitudeTrue = myAircraft.getAltitude().value(CLengthUnit::ft());
pos.heading = ownAircraft().getHeading().value(CAngleUnit::deg()); pos.heading = myAircraft.getHeading().value(CAngleUnit::deg());
pos.pitch = ownAircraft().getPitch().value(CAngleUnit::deg()); pos.pitch = myAircraft.getPitch().value(CAngleUnit::deg());
pos.bank = ownAircraft().getBank().value(CAngleUnit::deg()); pos.bank = myAircraft.getBank().value(CAngleUnit::deg());
pos.latitude = ownAircraft().latitude().value(CAngleUnit::deg()); pos.latitude = myAircraft.latitude().value(CAngleUnit::deg());
pos.longitude = ownAircraft().longitude().value(CAngleUnit::deg()); pos.longitude = myAircraft.longitude().value(CAngleUnit::deg());
pos.groundSpeed = ownAircraft().getGroundSpeed().value(CSpeedUnit::kts()); pos.groundSpeed = myAircraft.getGroundSpeed().value(CSpeedUnit::kts());
pos.rating = vatPilotRatingUnknown; pos.rating = vatPilotRatingUnknown;
pos.transponderCode = static_cast<qint16>(ownAircraft().getTransponderCode()); pos.transponderCode = static_cast<qint16>(myAircraft.getTransponderCode());
pos.transponderMode = vatTransponderModeStandby; pos.transponderMode = vatTransponderModeStandby;
switch (ownAircraft().getTransponderMode()) switch (myAircraft.getTransponderMode())
{ {
case CTransponder::ModeC: pos.transponderMode = vatTransponderModeCharlie; break; case CTransponder::ModeC: pos.transponderMode = vatTransponderModeCharlie; break;
case CTransponder::StateIdent: pos.transponderMode = vatTransponderModeIdent; break; case CTransponder::StateIdent: pos.transponderMode = vatTransponderModeIdent; break;
@@ -422,20 +423,21 @@ namespace BlackCore
Vat_SendClientQuery(m_net.data(), vatClientQueryInfo, toFSD(callsign)); Vat_SendClientQuery(m_net.data(), vatClientQueryInfo, toFSD(callsign));
} }
void CNetworkVatlib::sendInterimPosition(const CCallsignSet &receivers) void CNetworkVatlib::sendInterimPositions(const CCallsignSet &receivers)
{ {
Q_ASSERT_X(isConnected(), "CNetworkVatlib", "Can't send to server when disconnected"); Q_ASSERT_X(isConnected(), "CNetworkVatlib", "Can't send to server when disconnected");
if (receivers.isEmpty()) { return; }
CSimulatedAircraft myAircraft(ownAircraft());
if (this->m_loginMode == LoginNormal) if (this->m_loginMode == LoginNormal)
{ {
VatInterimPilotPosition pos; VatInterimPilotPosition pos;
// TODO: we need to distinguish true and pressure altitude // TODO: we need to distinguish true and pressure altitude
pos.altitudeTrue = ownAircraft().getAltitude().value(CLengthUnit::ft()); pos.altitudeTrue = myAircraft.getAltitude().value(CLengthUnit::ft());
pos.heading = ownAircraft().getHeading().value(CAngleUnit::deg()); pos.heading = myAircraft.getHeading().value(CAngleUnit::deg());
pos.pitch = ownAircraft().getPitch().value(CAngleUnit::deg()); pos.pitch = myAircraft.getPitch().value(CAngleUnit::deg());
pos.bank = ownAircraft().getBank().value(CAngleUnit::deg()); pos.bank = myAircraft.getBank().value(CAngleUnit::deg());
pos.latitude = ownAircraft().latitude().value(CAngleUnit::deg()); pos.latitude = myAircraft.latitude().value(CAngleUnit::deg());
pos.longitude = ownAircraft().longitude().value(CAngleUnit::deg()); pos.longitude = myAircraft.longitude().value(CAngleUnit::deg());
for (const auto &receiver : receivers) for (const auto &receiver : receivers)
{ {
@@ -615,7 +617,8 @@ namespace BlackCore
if (modelString.isEmpty()) { modelString = defaultModelString(); } if (modelString.isEmpty()) { modelString = defaultModelString(); }
QStringList data { { "0" }, icao.getAirlineDesignator(), icao.getAircraftDesignator(), QStringList data { { "0" }, icao.getAirlineDesignator(), icao.getAircraftDesignator(),
{ "" }, { "" }, { "" }, { "" }, icao.getAircraftCombinedType(), modelString }; { "" }, { "" }, { "" }, { "" }, icao.getAircraftCombinedType(), modelString
};
sendCustomPacket(callsign, "FSIPIR", data); sendCustomPacket(callsign, "FSIPIR", data);
} }
@@ -627,7 +630,8 @@ namespace BlackCore
if (modelString.isEmpty()) { modelString = defaultModelString(); } if (modelString.isEmpty()) { modelString = defaultModelString(); }
QStringList data { { "0" }, icao.getAirlineDesignator(), icao.getAircraftDesignator(), QStringList data { { "0" }, icao.getAirlineDesignator(), icao.getAircraftDesignator(),
{ "" }, { "" }, { "" }, { "" }, icao.getAircraftCombinedType(), modelString }; { "" }, { "" }, { "" }, { "" }, icao.getAircraftCombinedType(), modelString
};
sendCustomPacket(callsign, "FSIPI", data); sendCustomPacket(callsign, "FSIPI", data);
} }
@@ -877,11 +881,11 @@ namespace BlackCore
{ {
switch (type) switch (type)
{ {
case vatInfoQueryTypeFreq: emit cbvar_cast(cbvar)->frequencyReplyReceived(cbvar_cast(cbvar)->fromFSD(callsign), CFrequency(cbvar_cast(cbvar)->fromFSD(data).toFloat(), CFrequencyUnit::MHz())); break; case vatClientQueryFreq: emit cbvar_cast(cbvar)->frequencyReplyReceived(cbvar_cast(cbvar)->fromFSD(callsign), CFrequency(cbvar_cast(cbvar)->fromFSD(data).toFloat(), CFrequencyUnit::MHz())); break;
case vatInfoQueryTypeServer: emit cbvar_cast(cbvar)->serverReplyReceived(cbvar_cast(cbvar)->fromFSD(callsign), cbvar_cast(cbvar)->fromFSD(data)); break; case vatClientQueryServer: emit cbvar_cast(cbvar)->serverReplyReceived(cbvar_cast(cbvar)->fromFSD(callsign), cbvar_cast(cbvar)->fromFSD(data)); break;
case vatInfoQueryTypeAtc: emit cbvar_cast(cbvar)->atcReplyReceived(CCallsign(cbvar_cast(cbvar)->fromFSD(data2), CCallsign::Atc), *data == 'Y'); break; case vatClientQueryAtc: emit cbvar_cast(cbvar)->atcReplyReceived(CCallsign(cbvar_cast(cbvar)->fromFSD(data2), CCallsign::Atc), *data == 'Y'); break;
case vatInfoQueryTypeName: emit cbvar_cast(cbvar)->realNameReplyReceived(cbvar_cast(cbvar)->fromFSD(callsign), cbvar_cast(cbvar)->fromFSD(data)); break; case vatClientQueryName: emit cbvar_cast(cbvar)->realNameReplyReceived(cbvar_cast(cbvar)->fromFSD(callsign), cbvar_cast(cbvar)->fromFSD(data)); break;
case vatInfoQueryTypeIP: emit cbvar_cast(cbvar)->ipReplyReceived(cbvar_cast(cbvar)->fromFSD(data)); break; case vatClientQueryIP: emit cbvar_cast(cbvar)->ipReplyReceived(cbvar_cast(cbvar)->fromFSD(data)); break;
default: break; default: break;
} }
} }

View File

@@ -81,7 +81,7 @@ namespace BlackCore
virtual void sendIcaoCodesQuery(const BlackMisc::Aviation::CCallsign &callsign) override; virtual void sendIcaoCodesQuery(const BlackMisc::Aviation::CCallsign &callsign) override;
virtual void sendFrequencyQuery(const BlackMisc::Aviation::CCallsign &callsign) override; virtual void sendFrequencyQuery(const BlackMisc::Aviation::CCallsign &callsign) override;
virtual void sendUserInfoQuery(const BlackMisc::Aviation::CCallsign &callsign) override; virtual void sendUserInfoQuery(const BlackMisc::Aviation::CCallsign &callsign) override;
virtual void sendInterimPosition(const BlackMisc::Aviation::CCallsignSet &receiver) override; virtual void sendInterimPositions(const BlackMisc::Aviation::CCallsignSet &receiver) override;
//! @} //! @}
//! \name Weather slots //! \name Weather slots