From c3a75bb900678bbab017b0f69133e10aaeded0e4 Mon Sep 17 00:00:00 2001 From: Sven Czarnian Date: Sun, 19 Dec 2021 12:23:23 +0100 Subject: [PATCH] add a menu to force set runways --- src/PlugIn.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++------ src/PlugIn.h | 36 ++++++++++------ 2 files changed, 123 insertions(+), 24 deletions(-) diff --git a/src/PlugIn.cpp b/src/PlugIn.cpp index 7e038cc..16f38a4 100644 --- a/src/PlugIn.cpp +++ b/src/PlugIn.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -71,6 +72,7 @@ PlugIn::PlugIn() : this->RegisterTagItemType("Delta time", static_cast(PlugIn::TagItemElement::DeltaTime)); this->RegisterTagItemType("Fixed plan indicator", static_cast(PlugIn::TagItemElement::FixedPlanIndicator)); this->RegisterTagItemFunction("Force planning", static_cast(PlugIn::TagItemFunction::ForceToBackendMenu)); + this->RegisterTagItemFunction("Runway selection", static_cast(PlugIn::TagItemFunction::RunwaySelectMenu)); this->DisplayUserMessage(PLUGIN_NAME, "INFO", (std::string("Loaded ") + PLUGIN_NAME + " " + PLUGIN_VERSION).c_str(), true, true, false, false, false); @@ -207,6 +209,8 @@ EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayN if (nullptr == this->m_screen) this->m_screen = std::make_shared(); + this->OnAirportRunwayActivityChanged(); + return this->m_screen.get(); } @@ -454,6 +458,10 @@ void PlugIn::generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarT report->set_allocated_dynamics(dynamics); report->set_allocated_position(coordinate); + auto selectedRwyIt = this->m_selectedRunway.find(radarTarget.GetCallsign()); + if (this->m_selectedRunway.cend() != selectedRwyIt) + report->set_requestedrunway(selectedRwyIt->second); + /* set the report time */ std::stringstream stream; const auto reportTime = std::chrono::utc_clock::now(); @@ -476,8 +484,6 @@ bool PlugIn::OnCompileCommand(const char* cmdline) { if (std::string::npos != message.find("RELOAD")) { this->validateBackendData(); - this->m_sweatboxValid = false; - this->m_playbackValid = false; retval = true; } else if (std::string::npos != message.find("SWEATBOX")) { @@ -603,9 +609,9 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE this->OpenPopupList(area, "AMAN", 1); bool inList = this->m_forcedToBackendCallsigns.cend() != std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), callsign); this->AddPopupListElement("Add to AMAN", "", static_cast(PlugIn::TagItemFunction::ForceToBackendSelect), - false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, true == inList); + false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, true == inList); this->AddPopupListElement("Remove from AMAN", "", static_cast(PlugIn::TagItemFunction::ForceToBackendSelect), - false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList); + false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList); break; } case PlugIn::TagItemFunction::ForceToBackendSelect: @@ -633,6 +639,45 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE break; } + case PlugIn::TagItemFunction::RunwaySelectMenu: + { + std::string destination(radarTarget.GetCorrelatedFlightPlan().GetFlightPlanData().GetDestination()); + std::transform(destination.begin(), destination.end(), destination.begin(), ::toupper); + + std::lock_guard guard(this->m_updateQueueLock); + auto it = this->m_updateQueue.find(destination); + + if (this->m_updateQueue.cend() != it) { + this->OpenPopupList(area, "Select runway", 1); + bool inList = this->m_selectedRunway.find(callsign) != this->m_selectedRunway.cend(); + this->AddPopupListElement("Remove", "", static_cast(PlugIn::TagItemFunction::RunwaySelect), + false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList); + + for (const auto& rwy : std::as_const(it->second.arrivalRunways)) + this->AddPopupListElement(rwy.c_str(), "", static_cast(PlugIn::TagItemFunction::RunwaySelect)); + } + + break; + } + case PlugIn::TagItemFunction::RunwaySelect: + { + std::lock_guard guard(this->m_updateQueueLock); + + if (0 == std::strcmp(itemString, "Remove")) { + auto it = this->m_selectedRunway.find(callsign); + if (this->m_selectedRunway.end() != it) + this->m_selectedRunway.erase(it); + } + else { + auto it = this->m_selectedRunway.find(callsign); + if (this->m_selectedRunway.end() != it) + it->second = itemString; + else + this->m_selectedRunway.insert({ callsign, itemString }); + } + + break; + } default: break; } @@ -651,8 +696,17 @@ void PlugIn::addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget) { #pragma warning(default: 4244) auto it = this->m_updateQueue.find(destination); - if (this->m_updateQueue.end() != it) - it->second.push_back(radarTarget.GetCallsign()); + if (this->m_updateQueue.end() != it) { + /* check that an active arrival runway is selected */ + auto selectedIt = this->m_selectedRunway.find(radarTarget.GetCallsign()); + if (this->m_selectedRunway.end() != selectedIt) { + auto activeRwyIt = std::find(it->second.arrivalRunways.cbegin(), it->second.arrivalRunways.cend(), selectedIt->second); + if (it->second.arrivalRunways.cend() == activeRwyIt) + this->m_selectedRunway.erase(selectedIt); + } + + it->second.inboundUpdates.push_back(radarTarget.GetCallsign()); + } } void PlugIn::updateInbound(EuroScopePlugIn::CRadarTarget& radarTarget) { @@ -726,8 +780,15 @@ void PlugIn::updateSequence(std::shared_ptr& sequence) { } } - if (false == found) + if (false == found) { + /* delete the forced runway selection */ + std::lock_guard guard(this->m_updateQueueLock); + auto selected = this->m_selectedRunway.find(it->first); + if (this->m_selectedRunway.end() != selected) + this->m_selectedRunway.erase(selected); + it = this->m_inbounds.erase(it); + } else ++it; } @@ -764,7 +825,7 @@ void PlugIn::OnTimer(int counter) { if (true == this->m_connectedToNetwork) { std::lock_guard guardUpdate(this->m_updateQueueLock); for (auto& airport : this->m_updateQueue) - airport.second.clear(); + airport.second.inboundUpdates.clear(); std::lock_guard guardInbound(this->m_inboundsQueueLock); this->m_inbounds.clear(); @@ -785,10 +846,10 @@ void PlugIn::OnTimer(int counter) { aman::AircraftUpdate update; update.set_airport(airport.first); - if (0 != airport.second.size()) { + if (0 != airport.second.inboundUpdates.size()) { for (auto target = this->RadarTargetSelectFirst(); true == target.IsValid(); target = this->RadarTargetSelectNext(target)) { - auto it = std::find(airport.second.begin(), airport.second.end(), target.GetCallsign()); - if (airport.second.end() != it) { + auto it = std::find(airport.second.inboundUpdates.begin(), airport.second.inboundUpdates.end(), target.GetCallsign()); + if (airport.second.inboundUpdates.end() != it) { auto report = update.add_reports(); this->generateAircraftReportMessage(target, report); } @@ -802,8 +863,34 @@ void PlugIn::OnTimer(int counter) { else this->updateSequence(sequence); - airport.second.clear(); + airport.second.inboundUpdates.clear(); } this->m_updateQueueLock.unlock(); } + +void PlugIn::OnAirportRunwayActivityChanged() { + std::lock_guard guard(this->m_updateQueueLock); + + /* cleanup the arrival airports */ + for (auto& airport : this->m_updateQueue) + airport.second.arrivalRunways.clear(); + + EuroScopePlugIn::CSectorElement rwy; + for (rwy = this->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_RUNWAY); true == rwy.IsValid(); + rwy = this->SectorFileElementSelectNext(rwy, EuroScopePlugIn::SECTOR_ELEMENT_RUNWAY)) { + /* remove leading and trailing whitespaces */ + std::string airport(rwy.GetAirportName()); + airport = std::regex_replace(airport, std::regex("^ +| +$|( ) +"), "$1"); + + if (true == rwy.IsElementActive(false, 0) || true == rwy.IsElementActive(false, 1)) { + auto airportData = this->m_updateQueue.find(airport); + if (this->m_updateQueue.end() != airportData) { + if (true == rwy.IsElementActive(false, 0)) + airportData->second.arrivalRunways.push_back(rwy.GetRunwayName(0)); + if (true == rwy.IsElementActive(false, 1)) + airportData->second.arrivalRunways.push_back(rwy.GetRunwayName(1)); + } + } + } +} diff --git a/src/PlugIn.h b/src/PlugIn.h index 9995e1d..abe7df8 100644 --- a/src/PlugIn.h +++ b/src/PlugIn.h @@ -37,10 +37,17 @@ namespace aman { */ enum class TagItemFunction { ForceToBackendMenu = 0, /**< Opens the menu to force tracks */ - ForceToBackendSelect = 1 /**< Reacts on controller selection */ + ForceToBackendSelect = 1, /**< Reacts on controller selection */ + RunwaySelectMenu = 2, /**< Opens the runway selection menu */ + RunwaySelect = 3 /**< Selects the runway */ }; private: + struct AirportData { + std::vector arrivalRunways; + std::list inboundUpdates; + }; + enum class TagItemElement { EstimatedTimeOfArrival = 0, PlannedTimeOfArrival = 1, @@ -58,17 +65,18 @@ namespace aman { static void distanceToPredictedIaf(const EuroScopePlugIn::CRadarTarget& radarTarget, const EuroScopePlugIn::CFlightPlan& flightPlan, const EuroScopePlugIn::CPosition& iafPosition, aman::AircraftReport* report); - Communication m_configuration; - std::shared_ptr m_screen; - std::mutex m_updateQueueLock; - std::map> m_updateQueue; - std::mutex m_inboundsQueueLock; - std::map m_inbounds; - std::list m_forcedToBackendCallsigns; - bool m_compatible; - bool m_connectedToNetwork; - bool m_sweatboxValid; - bool m_playbackValid; + Communication m_configuration; + std::shared_ptr m_screen; + std::mutex m_updateQueueLock; + std::map m_updateQueue; + std::mutex m_inboundsQueueLock; + std::map m_inbounds; + std::map m_selectedRunway; + std::list m_forcedToBackendCallsigns; + bool m_compatible; + bool m_connectedToNetwork; + bool m_sweatboxValid; + bool m_playbackValid; public: /** @@ -145,5 +153,9 @@ namespace aman { * @param[in] flightPlan The disconnected flight plan */ void OnFlightPlanDisconnect(EuroScopePlugIn::CFlightPlan flightPlan) override; + /** + * @brief Called as soon as a runway configuration changed + */ + void OnAirportRunwayActivityChanged() override; }; }