Skip to content

Commit

Permalink
Merge pull request #535 from AndyTWF/ecfmp-integration
Browse files Browse the repository at this point in the history
ECFMP Integration
  • Loading branch information
AndyTWF authored Sep 16, 2023
2 parents 73c9b51 + 4c989d5 commit 3c08d7e
Show file tree
Hide file tree
Showing 65 changed files with 2,838 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
[submodule "third_party/cpp-httplib"]
path = third_party/cpp-httplib
url = [email protected]:yhirose/cpp-httplib.git
[submodule "third_party/ecfmp"]
path = third_party/ecfmp
url = [email protected]:ECFMP/plugin.git
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
################################################################################
# Sub-projects
################################################################################
add_subdirectory(third_party/ecfmp/src)
add_subdirectory(src/loader)
add_subdirectory(src/plugin)
add_subdirectory(src/updater)
Expand Down
1 change: 1 addition & 0 deletions docs/TAG_FUNCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
9020 - Trigger Missed Approach
9021 - Acknowledge Missed Approach
9022 - Open Squawk Assignment Menu
9023 - Display Relevant ECFMP Flow Measures
1 change: 1 addition & 0 deletions docs/TAG_ITEMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
128 - SELCAL Code
129 - SELCAL Code With Separator
130 - Missed Approach Indicator
131 - Relevant ECFMP Flow Measures
22 changes: 22 additions & 0 deletions resource/UKControllerPlugin.rc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,15 @@ BEGIN
LTEXT "Please go to your web browser and log in to the UK Controller Plugin page. This window will close automatically once your API key has been received. If you are unable to find the page, you can click the button below to re-open it.",IDC_API_KEY_STATIC,7,7,249,89
END

IDD_FLOW_MEASURE_LIST DIALOGEX 0, 0, 367, 297
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Close",IDOK,310,276,50,14
EDITTEXT IDC_FLOW_MEASURES_INFO,7,7,353,264,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL
END


/////////////////////////////////////////////////////////////////////////////
//
Expand Down Expand Up @@ -497,6 +506,14 @@ BEGIN
TOPMARGIN, 7
BOTTOMMARGIN, 120
END

IDD_FLOW_MEASURE_LIST, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 360
TOPMARGIN, 7
BOTTOMMARGIN, 290
END
END
#endif // APSTUDIO_INVOKED

Expand Down Expand Up @@ -586,6 +603,11 @@ BEGIN
0
END

IDD_FLOW_MEASURE_LIST AFX_DIALOG_LAYOUT
BEGIN
0
END


/////////////////////////////////////////////////////////////////////////////
//
Expand Down
5 changes: 4 additions & 1 deletion resource/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#define IDD_MISSED_APPROACH_ACKNOWLEDGE 139
#define IDD_DEPARTURE_RELEASE_REJECT 141
#define IDD_API_KEY_REPLACE 143
#define IDD_FLOW_MEASURE_LIST 145
#define IDC_CHECK_DEGRADING 1001
#define IDC_CHECK_FADING 1002
#define IDC_CHECK_AA 1003
Expand Down Expand Up @@ -133,13 +134,15 @@
#define IDC_DEPARTURE_RELEASE_APPROVE_CALLSIGN 1087
#define MISSED_APPROACH_DRAW_DURATION 1087
#define IDC_RELEASE_REJECT_REMARKS 1087
#define IDC_FLOW_MEASURES_DETAILS 1087
#define IDC_NOTES_STATIC 1088
#define IDC_HOLD_PARAMS_MIN_STATIC 1089
#define IDC_NOTIFICATION_BODY 1089
#define IDC_HOLD_PARAMS_MAX_STATIC 1090
#define IDC_HOLD_MIN_SPIN 1091
#define IDC_HOLD_MAX 1092
#define IDC_HOLD_MAXIMUM 1092
#define IDC_FLOW_MEASURES_INFO 1092
#define IDC_SPIN2 1093
#define IDC_HOLD_MAX_SPIN 1093
#define IDC_NOTIFICATION_LINK 1094
Expand Down Expand Up @@ -209,7 +212,7 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 145
#define _APS_NEXT_RESOURCE_VALUE 147
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1146
#define _APS_NEXT_SYMED_VALUE 101
Expand Down
8 changes: 8 additions & 0 deletions src/plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(PROJECT_NAME UKControllerPluginCore)
project(UKControllerPluginCore)

################################################################################
# Source groups
Expand Down Expand Up @@ -176,6 +177,10 @@ set(src__dependency
)
source_group("src\\dependency" FILES ${src__dependency})

set(src__ecfmp

ecfmp/ECFMPModuleFactory.cpp ecfmp/ECFMPModuleFactory.h ecfmp/Logger.cpp ecfmp/Logger.h ecfmp/HttpClient.cpp ecfmp/HttpClient.h ecfmp/ECFMPBootstrapProvider.cpp ecfmp/ECFMPBootstrapProvider.h ecfmp/TriggerEcfmpEventLoop.cpp ecfmp/TriggerEcfmpEventLoop.h ecfmp/AircraftFlowMeasureMap.cpp ecfmp/AircraftFlowMeasureMap.h ecfmp/AircraftFlowMeasureMapInterface.h ecfmp/AircraftFlowMeasureTagItem.cpp ecfmp/AircraftFlowMeasureTagItem.h ecfmp/ListAircraftFlowMeasures.cpp ecfmp/ListAircraftFlowMeasures.h ecfmp/AircraftFlowMeasuresDialog.cpp ecfmp/AircraftFlowMeasuresDialog.h ecfmp/HomeFirsFlowMeasureFilter.cpp ecfmp/HomeFirsFlowMeasureFilter.h ecfmp/ControllerFlowMeasureRelevance.cpp ecfmp/ControllerFlowMeasureRelevance.h ecfmp/ECFMPCustomMeasureFilterWrapper.cpp ecfmp/ECFMPCustomMeasureFilterWrapper.h ecfmp/ECFMPCustomMeasureFilter.h)

set(src__euroscope
"euroscope/AsrEventHandlerCollection.cpp"
"euroscope/AsrEventHandlerCollection.h"
Expand Down Expand Up @@ -975,6 +980,7 @@ set(ALL_FILES
${src__datablock}
${src__departure}
${src__dependency}
${src__ecfmp}
${src__euroscope}
${src__eventhandler}
${src__flightinformationservice}
Expand Down Expand Up @@ -1155,11 +1161,13 @@ endif()
################################################################################
add_dependencies(${PROJECT_NAME}
UKControllerPluginUtils
ecfmp_sdk
)

# Link with other targets.
target_link_libraries(${PROJECT_NAME} PUBLIC
UKControllerPluginUtils
ecfmp_sdk
)

set(ADDITIONAL_LIBRARY_DEPENDENCIES
Expand Down
2 changes: 2 additions & 0 deletions src/plugin/bootstrap/BootstrapProviderCollectionFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#include "BootstrapProviderCollection.h"
#include "BootstrapProviderCollectionFactory.h"
#include "approach/ApproachBootstrapProvider.h"
#include "ecfmp/ECFMPBootstrapProvider.h"
#include "intention/IntentionCodeBootstrapProvider.h"

namespace UKControllerPlugin::Bootstrap {
auto Make() -> std::unique_ptr<BootstrapProviderCollection>
{
auto collection = std::make_unique<BootstrapProviderCollection>();
collection->AddProvider(std::make_unique<Approach::ApproachBootstrapProvider>());
collection->AddProvider(std::make_unique<ECFMP::ECFMPBootstrapProvider>());
collection->AddProvider(std::make_unique<IntentionCode::IntentionCodeBootstrapProvider>());

return collection;
Expand Down
10 changes: 10 additions & 0 deletions src/plugin/bootstrap/ModuleFactories.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ModuleFactories.h"
#include "approach/ApproachModuleFactory.h"
#include "ecfmp/ECFMPModuleFactory.h"
#include "intention/IntentionCodeModuleFactory.h"

namespace UKControllerPlugin::Bootstrap {
Expand All @@ -24,4 +25,13 @@ namespace UKControllerPlugin::Bootstrap {

return *intentionCode;
}

auto ModuleFactories::ECFMP() -> ECFMP::ECFMPModuleFactory&
{
if (!ecfmp) {
ecfmp = std::make_unique<ECFMP::ECFMPModuleFactory>();
}

return *ecfmp;
}
} // namespace UKControllerPlugin::Bootstrap
6 changes: 6 additions & 0 deletions src/plugin/bootstrap/ModuleFactories.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ namespace UKControllerPlugin {
namespace Approach {
class ApproachModuleFactory;
} // namespace Approach
namespace ECFMP {
class ECFMPModuleFactory;
} // namespace ECFMP
namespace IntentionCode {
class IntentionCodeModuleFactory;
} // namespace IntentionCode
Expand All @@ -23,12 +26,15 @@ namespace UKControllerPlugin::Bootstrap {
ModuleFactories();
~ModuleFactories();
[[nodiscard]] auto Approach() -> Approach::ApproachModuleFactory&;
[[nodiscard]] auto ECFMP() -> ECFMP::ECFMPModuleFactory&;
[[nodiscard]] auto IntentionCode() -> IntentionCode::IntentionCodeModuleFactory&;

private:
// The approach module
std::unique_ptr<Approach::ApproachModuleFactory> approach;

std::unique_ptr<ECFMP::ECFMPModuleFactory> ecfmp;

// The intention code module
std::unique_ptr<IntentionCode::IntentionCodeModuleFactory> intentionCode;
};
Expand Down
171 changes: 171 additions & 0 deletions src/plugin/ecfmp/AircraftFlowMeasureMap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#include "AircraftFlowMeasureMap.h"
#include "controller/ActiveCallsign.h"
#include "ECFMP/flowmeasure/FlowMeasure.h"
#include "euroscope/EuroScopeCFlightPlanInterface.h"
#include "euroscope/EuroScopeCRadarTargetInterface.h"
#include "euroscope/EuroscopePluginLoopbackInterface.h"

namespace UKControllerPlugin::ECFMP {

struct AircraftFlowMeasureMap::Impl
{
Impl(Euroscope::EuroscopePluginLoopbackInterface& plugin) : plugin(plugin)
{
}

void RemoveFlightplanFromCollection(Euroscope::EuroScopeCFlightPlanInterface& flightplan)
{
// No flow measures are relevant to this flight plan
if (!callsignFlowMeasureMap.contains(flightplan.GetCallsign())) {
return;
}

// Remove the flight plan from the flow measure's callsign map
for (const auto& flowMeasure : callsignFlowMeasureMap.at(flightplan.GetCallsign())) {
flowMeasureCallsignMap.at(flowMeasure).erase(flightplan.GetCallsign());
}

// Remove the callsign from the callsign map
callsignFlowMeasureMap.erase(flightplan.GetCallsign());
}

void RemoveFlowMeasureFromCollection(const ::ECFMP::FlowMeasure::FlowMeasure& measure)
{
// Measure never became active
if (!flowMeasureIdMap.contains(measure.Id())) {
return;
}

const auto collectionMeasure = flowMeasureIdMap.at(measure.Id());

// Remove from the callsign map
for (const auto& callsign : flowMeasureCallsignMap.at(collectionMeasure)) {
callsignFlowMeasureMap.at(callsign).erase(collectionMeasure);
}

// Remove from the map by measure and id
flowMeasureCallsignMap.erase(collectionMeasure);
flowMeasureIdMap.erase(measure.Id());
}

void FlowMeasureActivated(const std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>& measure)
{
if (flowMeasureIdMap.contains(measure->Id())) {
LogWarning("Flow measure with id " + std::to_string(measure->Id()) + " already exists in the map");
return;
}

// Add the flow measure to the map by id
flowMeasureIdMap.emplace(measure->Id(), measure);

// Check each of the flightplans and see if it applies to them
plugin.ApplyFunctionToAllFlightplans([&measure, this](
const Euroscope::EuroScopeCFlightPlanInterface& flightplan,
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget) {
if (measure->ApplicableToAircraft(flightplan.GetEuroScopeObject(), radarTarget.GetEuroScopeObject())) {
callsignFlowMeasureMap[flightplan.GetCallsign()].insert(measure);
flowMeasureCallsignMap[measure].insert(flightplan.GetCallsign());
}
});
}

void MapFlightplanToActiveFlowMeasures(
Euroscope::EuroScopeCFlightPlanInterface& flightPlan,
Euroscope::EuroScopeCRadarTargetInterface& radarTarget)
{
for (const auto& [id, measure] : flowMeasureIdMap) {
if (measure->ApplicableToAircraft(flightPlan.GetEuroScopeObject(), radarTarget.GetEuroScopeObject())) {
callsignFlowMeasureMap[flightPlan.GetCallsign()].insert(measure);
flowMeasureCallsignMap[measure].insert(flightPlan.GetCallsign());
}
}
}

void ClearMaps()
{
flowMeasureIdMap.clear();
callsignFlowMeasureMap.clear();
flowMeasureCallsignMap.clear();
}

// The plugin, used to map over flightplans
Euroscope::EuroscopePluginLoopbackInterface& plugin;

// Map of callsigns to flow measures and vice versa
std::map<int, std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>> flowMeasureIdMap;
std::map<std::string, std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>>>
callsignFlowMeasureMap;
std::map<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>, std::unordered_set<std::string>>
flowMeasureCallsignMap;

// An empty set for use when we dont have a callsign
std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>> emptyFlowMeasureSet;
};

AircraftFlowMeasureMap::AircraftFlowMeasureMap(Euroscope::EuroscopePluginLoopbackInterface& plugin)
: impl(std::make_unique<Impl>(plugin))
{
}

AircraftFlowMeasureMap::~AircraftFlowMeasureMap() = default;

void AircraftFlowMeasureMap::OnEvent(const ::ECFMP::Plugin::FlowMeasureActivatedEvent& event)
{
impl->FlowMeasureActivated(event.flowMeasure);
}

void AircraftFlowMeasureMap::OnEvent(const ::ECFMP::Plugin::FlowMeasureExpiredEvent& event)
{
impl->RemoveFlowMeasureFromCollection(*event.flowMeasure);
}

void AircraftFlowMeasureMap::OnEvent(const ::ECFMP::Plugin::FlowMeasureWithdrawnEvent& event)
{
impl->RemoveFlowMeasureFromCollection(*event.flowMeasure);
}

void AircraftFlowMeasureMap::FlightPlanEvent(
Euroscope::EuroScopeCFlightPlanInterface& flightPlan, Euroscope::EuroScopeCRadarTargetInterface& radarTarget)
{
impl->RemoveFlightplanFromCollection(flightPlan);
impl->MapFlightplanToActiveFlowMeasures(flightPlan, radarTarget);
}

void AircraftFlowMeasureMap::FlightPlanDisconnectEvent(Euroscope::EuroScopeCFlightPlanInterface& flightPlan)
{
impl->RemoveFlightplanFromCollection(flightPlan);
}

const std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>>&
AircraftFlowMeasureMap::GetFlowMeasuresForCallsign(const std::string& callsign) const
{
return impl->callsignFlowMeasureMap.contains(callsign) ? impl->callsignFlowMeasureMap.at(callsign)
: impl->emptyFlowMeasureSet;
}

void AircraftFlowMeasureMap::ControllerFlightPlanDataEvent(
Euroscope::EuroScopeCFlightPlanInterface& flightPlan, int dataType)
{
// No-op
}

void AircraftFlowMeasureMap::ActiveCallsignAdded(const Controller::ActiveCallsign& callsign)
{
// Only interested in user callsigns
if (!callsign.GetIsUser()) {
return;
}

impl->ClearMaps();
}

void AircraftFlowMeasureMap::ActiveCallsignRemoved(const Controller::ActiveCallsign& callsign)
{
// Only interested in user callsigns
if (!callsign.GetIsUser()) {
return;
}

impl->ClearMaps();
}
} // namespace UKControllerPlugin::ECFMP
Loading

0 comments on commit 3c08d7e

Please sign in to comment.