From 3e29aa1747d3cd9692aa5d78a7476b0c3c73c14b Mon Sep 17 00:00:00 2001 From: Phil7789 <87429599+Phil7789@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:24:04 +0100 Subject: [PATCH 1/4] Update Changelog.txt --- Changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 06b3c0d..993365e 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -8,12 +8,15 @@ * FPLN - temporarily added scratch pad info which callsign used the sync command * CONF - collapsing SID or TRANS base when consecutive characters are the same as new Navigraph data collapses those names which are then present in the sector file (#358) * FPLN - add squawk queue with a grace period to fetch assignements that were too fast. Squawk assignement works now also in auto-mode and with our own included TopSky assign function (fast click sequence). Note: CCAMS only supported in auto-mode as there currently is no additional function implemented (currently not planned) (#388) + * When using our internal TopSky auto-assign function the selected flight plan will be moved to the front of the queue :gear: **Changed Features / Behaviour** * GEN - changed topsky and ccams lookup check to lower case * FPLN - added checks to _CTL_ and _AUTO_ scratch pad entries to not trigger sync queue processing * FPLN - moved clearance flag sync release to flight plan data update * FPLN - removed syncing of unset clearance flag - only if the clearance flag is set it will be synced +* ATC - changed frequency matching to consider ICAO (e.g. EDGG, EDDF) and facility (e.g. DEL, GND) and only matches the frequency if ICAO and facility also match in case close but different stations share the same frequency + * flight information stations are determined by "Information" in the name of the station :lady_beetle: **Fixes** * CONF - fixed a crash when SID health check was triggered for different SID numbers due to an accidentally wrong type assignment From 263892c0b46c7dd75cb387be3581c95b5cf8f055 Mon Sep 17 00:00:00 2001 From: Phil7789 <87429599+Phil7789@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:24:45 +0100 Subject: [PATCH 2/4] Add error codes --- constants.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/constants.h b/constants.h index 1e9b7fa..295483e 100644 --- a/constants.h +++ b/constants.h @@ -116,5 +116,7 @@ const std::string ERROR_CONF_DISPLAY = "E052"; const std::string ERROR_CMD_ATCICAO = "E060"; const std::string ERROR_ATC_ICAOSPLIT = "E070"; +const std::string ERROR_ATC_ICAOSPLIT_FREQ_OTH = "E070-1"; +const std::string ERROR_ATC_ICAOSPLIT_FREQ_MY = "E070-2"; const std::string ERROR_REQ_RWYSPLIT = "E080"; From 190e5d2824b2880518a249c417d14b056c8fb01d Mon Sep 17 00:00:00 2001 From: Phil7789 <87429599+Phil7789@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:25:02 +0100 Subject: [PATCH 3/4] Add facility determination --- eseparser.cpp | 26 ++++++++++++++++++++++++++ eseparser.h | 5 +++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/eseparser.cpp b/eseparser.cpp index b37f61a..4b3b173 100644 --- a/eseparser.cpp +++ b/eseparser.cpp @@ -94,9 +94,35 @@ void vsid::EseParser::line(Section s, std::string_view l) try { + int facility = 0; + + if (atcVec.at(1).find("Information") != std::string::npos) facility = 1; + else + { + std::optional callsignFac = std::nullopt; + + if(std::vector callsignSplit = vsid::utils::split(atcVec.at(0), '_'); callsignSplit.size() > 2) + callsignFac = callsignSplit.at(2); + else if(callsignSplit.size() > 1) + callsignFac = callsignSplit.at(1); + + + if (callsignFac) + { + const std::string& fac = *callsignFac; + + if (fac == "DEL") facility = 2; + else if (fac == "GND") facility = 3; + else if (fac == "TWR") facility = 4; + else if (fac == "APP" || fac == "DEP") facility = 5; + else if (fac == "CTR") facility = 6; + } + } + this->sectionAtc_.emplace( atcVec.at(0), // callsign atcVec.at(3), // si + facility, std::stod(atcVec.at(2)), // freq visPoints // additional vis points ); diff --git a/eseparser.h b/eseparser.h index 12e4941..6826f30 100644 --- a/eseparser.h +++ b/eseparser.h @@ -39,11 +39,12 @@ namespace vsid { std::string callsign; std::string si; + int facility; double freq; std::vector visPoints; - explicit SectionAtc(std::string callsign, std::string si, double freq, std::vector visPoints) : - callsign(std::move(callsign)), si(std::move(si)), freq(freq), visPoints(std::move(visPoints)) {} + explicit SectionAtc(std::string callsign, std::string si, int facility, double freq, std::vector visPoints) : + callsign(std::move(callsign)), si(std::move(si)), facility(facility), freq(freq), visPoints(std::move(visPoints)) {} bool operator<(const vsid::SectionAtc& other) const noexcept { From f95c86708360b5eb11137662a71ac1d972a7bcd4 Mon Sep 17 00:00:00 2001 From: Phil7789 <87429599+Phil7789@users.noreply.github.com> Date: Thu, 1 Jan 2026 20:26:03 +0100 Subject: [PATCH 4/4] Add freq match with callsign consideration --- vSIDPlugin.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++-------- vSIDPlugin.h | 12 ++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/vSIDPlugin.cpp b/vSIDPlugin.cpp index 6eb0f81..c498707 100644 --- a/vSIDPlugin.cpp +++ b/vSIDPlugin.cpp @@ -1604,7 +1604,7 @@ bool vsid::VSIDPlugin::outOfVis(EuroScopePlugIn::CFlightPlan& FlightPlan) { for (auto& atc : this->sectionAtc) { - if (myCallsign == atc.callsign || myFreq == atc.freq) + if (myCallsign == atc.callsign || atcFreqMatch(ControllerMyself(), atc)) { if (atc.visPoints.empty()) return true; @@ -1811,6 +1811,66 @@ void vsid::VSIDPlugin::addOrSetSquawk(const std::string& callsign, bool forceTS) } } } + +bool vsid::VSIDPlugin::atcFreqMatch(const EuroScopePlugIn::CController& other, const vsid::SectionAtc& local) +{ + if (other.GetPrimaryFrequency() != local.freq) + { + messageHandler->writeMessage("DEBUG", "[FREQ Match] other: " + std::to_string(other.GetPrimaryFrequency()) + + " is NOT local: " + std::to_string(local.freq), vsid::MessageHandler::DebugArea::Dev); + return false; + } + + const std::string atcCallsign = other.GetCallsign(); + const std::string myCallsign = local.callsign; + std::optional atcIcao = std::nullopt; + std::optional myIcao = std::nullopt; + + try + { + atcIcao = vsid::utils::split(atcCallsign, '_').at(0); + messageHandler->removeGenError(ERROR_ATC_ICAOSPLIT_FREQ_OTH + "_" + atcCallsign); + } + catch (std::out_of_range) + { + if (!messageHandler->genErrorsContains(ERROR_ATC_ICAOSPLIT_FREQ_OTH + "_" + atcCallsign)) + { + messageHandler->writeMessage("ERROR", "Failed to get ICAO part of other controller callsign \"" + atcCallsign + + "\" in Freq match check. Code: " + ERROR_ATC_ICAOSPLIT_FREQ_OTH); + messageHandler->addGenError(ERROR_ATC_ICAOSPLIT_FREQ_OTH + "_" + atcCallsign); + } + } + + try + { + myIcao = vsid::utils::split(myCallsign, '_').at(0); + messageHandler->removeGenError(ERROR_ATC_ICAOSPLIT_FREQ_MY + "_" + myCallsign); + } + catch (std::out_of_range) + { + if (!messageHandler->genErrorsContains(ERROR_ATC_ICAOSPLIT_FREQ_MY + "_" + myCallsign)) + { + messageHandler->writeMessage("ERROR", "Failed to get ICAO part of my controller callsign \"" + myCallsign + + "\" in Freq match check. Code: " + ERROR_ATC_ICAOSPLIT_FREQ_MY); + messageHandler->addGenError(ERROR_ATC_ICAOSPLIT_FREQ_MY + "_" + myCallsign); + } + } + + if (atcIcao && myIcao && *atcIcao == *myIcao && other.GetFacility() == local.facility) + { + messageHandler->writeMessage("DEBUG", "[FREQ Match] other: " + atcCallsign + "(" + std::to_string(other.GetPrimaryFrequency()) + + ") IS local: " + myCallsign + "(" + std::to_string(local.freq) + ")", vsid::MessageHandler::DebugArea::Dev); + return true; + } + else if (other.GetFacility() != local.facility) // #dev - debugging purpose + { + messageHandler->writeMessage("DEBUG", "[FREQ Match] other fac: " + atcCallsign + "(" + std::to_string(other.GetFacility()) + + ") is NOT local fac: " + myCallsign + "(" + std::to_string(local.facility) + ")", vsid::MessageHandler::DebugArea::Dev); + return false; + + } + else return false; +} /* * END OWN FUNCTIONS */ @@ -4720,15 +4780,15 @@ void vsid::VSIDPlugin::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget void vsid::VSIDPlugin::OnControllerPositionUpdate(EuroScopePlugIn::CController Controller) { - std::string atcCallsign = Controller.GetCallsign(); + const std::string atcCallsign = Controller.GetCallsign(); std::string atcSI = Controller.GetPositionId(); - int atcFac = Controller.GetFacility(); - double atcFreq = Controller.GetPrimaryFrequency(); + const int atcFac = Controller.GetFacility(); + const double atcFreq = Controller.GetPrimaryFrequency(); std::string atcIcao; try { - atcIcao = vsid::utils::split(Controller.GetCallsign(), '_').at(0); + atcIcao = vsid::utils::split(atcCallsign, '_').at(0); messageHandler->removeGenError(ERROR_ATC_ICAOSPLIT + "_" + atcCallsign); } catch (std::out_of_range) @@ -4750,7 +4810,7 @@ void vsid::VSIDPlugin::OnControllerPositionUpdate(EuroScopePlugIn::CController C { for (const vsid::SectionAtc &sAtc : this->sectionAtc) { - if (atcCallsign == sAtc.callsign || atcFreq == sAtc.freq) + if (atcCallsign == sAtc.callsign || atcFreqMatch(Controller, sAtc)) { atcSI = sAtc.si; @@ -4855,11 +4915,6 @@ void vsid::VSIDPlugin::OnControllerPositionUpdate(EuroScopePlugIn::CController C } } - if (std::none_of(atcIcaos.begin(), atcIcaos.end(), [&](auto atcIcao) - { - return this->activeAirports.contains(atcIcao); - })) return; - for (const std::string& atcIcao : atcIcaos) { if (!this->activeAirports.contains(atcIcao)) continue; diff --git a/vSIDPlugin.h b/vSIDPlugin.h index 428a55d..33cc4c3 100644 --- a/vSIDPlugin.h +++ b/vSIDPlugin.h @@ -550,5 +550,17 @@ namespace vsid // Parameter: bool forceTS - if TopSky should be forced for squawk assignment //************************************ void addOrSetSquawk(const std::string& callsign, bool forceTS = false); + + //************************************ + // Description: Checks for frequency match and considers ICAO and facility parts matching + // Method: atcFreqMatch + // FullName: vsid::VSIDPlugin::atcFreqMatch + // Access: private + // Returns: bool + // Qualifier: + // Parameter: const EuroScopePlugIn::CController & other + // Parameter: const vsid::SectionAtc & local + //************************************ + bool atcFreqMatch(const EuroScopePlugIn::CController& other, const vsid::SectionAtc& local); }; }