Skip to content

Commit

Permalink
feat(missedapproach): Allow airfields to always alert regardless of s…
Browse files Browse the repository at this point in the history
…ervice provision (#384)

* Update static test

* Audio alert conditions

* Render when relevant

* Docs update
  • Loading branch information
AndyTWF committed Jan 4, 2022
1 parent 0108cd5 commit 5fe9fd7
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 18 deletions.
10 changes: 8 additions & 2 deletions docs/UserGuide/Features/MissedApproaches.md
Expand Up @@ -76,11 +76,17 @@ you that has initiated the missed approach.
### Service provisions

You may only be interested in missed approaches when you are providing a particular type of
service, e.g. Final Approach. You may select which services you wish to be alerted for,
service, e.g. Final Approach. You will be alerted to a missed approach at any airfield where you
are providing the given type of service.

### Airfields

Only airfields selected from the list will have their missed approaches alerted to you.
In some instances, it may be prudent to be warned of missed approaches at airfields that you don't directly control.
For example, Heathrow Director may want to know about missed approaches at Northolt and Farnborough, as this has a
direct impact on their arrival stream.

You may select any airfields recognised by the plugin. If a missed approach occurs at any of these airfields,
you will be alerted.

## ASR-specific settings

Expand Down
2 changes: 1 addition & 1 deletion resource/UKControllerPlugin.rc
Expand Up @@ -312,7 +312,7 @@ BEGIN
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,229,156,10
CONTROL "Draw line to missed approach aircraft",MISSED_APPROACH_LINE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,243,135,10
LTEXT "Alert me to missed approaches at these airfields:",MISSED_APPROACH_AIRFIELDS,7,133,157,8
LTEXT "Always alert me to missed approaches at these airfields:",MISSED_APPROACH_AIRFIELDS,7,133,181,8
CONTROL "",MISSED_APPROACH_AIRFIELD_LIST,"SysListView32",LVS_LIST | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,146,226,62
EDITTEXT MISSED_APPROACH_DRAW_DURATION,7,259,55,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Draw duration in seconds (1-9)",MISSED_APPROACH_DRAW_DURATION_TEXT,69,262,100,8
Expand Down
27 changes: 23 additions & 4 deletions src/plugin/missedapproach/MissedApproachAudioAlert.cpp
Expand Up @@ -35,7 +35,9 @@ namespace UKControllerPlugin::MissedApproach {
* 1. The user has elected to receive alerts for approaches created by them OR it the approach was not created by
* them.
* 2. The flightplan exists.
* 3. The user is providing a specified service at the aircrafts destination airfield.
* 3a. The destination airfield is an "Always Alert" airfield.
* OR
* 3b. The user is providing a specified service at the aircrafts destination airfield.
* @param missedApproach
* @return
*/
Expand All @@ -54,9 +56,26 @@ namespace UKControllerPlugin::MissedApproach {
return false;
}

const auto airfields =
this->airfieldServiceProvisions.GetAirfieldsWhereUserProvidingServices(this->options->ServiceProvisions());
return this->DestinationIsAlwaysAlert(*flightplan) || this->UserProvidingServicesAtDestination(*flightplan);
}

return std::find(airfields.cbegin(), airfields.cend(), flightplan->GetDestination()) != airfields.cend();
auto
MissedApproachAudioAlert::DestinationIsAlwaysAlert(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) const
-> bool
{
const auto alwaysAlertAirfields = this->options->Airfields();
return std::find(alwaysAlertAirfields.begin(), alwaysAlertAirfields.end(), flightplan.GetDestination()) !=
alwaysAlertAirfields.cend();
}

auto MissedApproachAudioAlert::UserProvidingServicesAtDestination(
const Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool
{
const auto airfieldsWhereProvidingService =
this->airfieldServiceProvisions.GetAirfieldsWhereUserProvidingServices(this->options->ServiceProvisions());
return std::find(
airfieldsWhereProvidingService.cbegin(),
airfieldsWhereProvidingService.cend(),
flightplan.GetDestination()) != airfieldsWhereProvidingService.cend();
}
} // namespace UKControllerPlugin::MissedApproach
5 changes: 5 additions & 0 deletions src/plugin/missedapproach/MissedApproachAudioAlert.h
Expand Up @@ -2,6 +2,7 @@

namespace UKControllerPlugin {
namespace Euroscope {
class EuroScopeCFlightPlanInterface;
class EuroscopePluginLoopbackInterface;
} // namespace Euroscope
namespace Ownership {
Expand Down Expand Up @@ -31,6 +32,10 @@ namespace UKControllerPlugin::MissedApproach {
void Play(const std::shared_ptr<class MissedApproach>& missedApproach) const;

private:
[[nodiscard]] auto DestinationIsAlwaysAlert(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) const
-> bool;
[[nodiscard]] auto
UserProvidingServicesAtDestination(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool;
[[nodiscard]] auto ShouldPlay(const std::shared_ptr<class MissedApproach>& missedApproach) const -> bool;

// Options for missed approaches
Expand Down
20 changes: 9 additions & 11 deletions src/plugin/missedapproach/MissedApproachRenderer.cpp
Expand Up @@ -40,21 +40,19 @@ namespace UKControllerPlugin::MissedApproach {
{
const auto airfieldsProvidingServices =
this->serviceProviders.GetAirfieldsWhereUserProvidingServices(this->options->ServiceProvisions());
const auto& renderFor = this->options->Airfields();
const auto& alwaysRenderFor = this->options->Airfields();

std::vector<std::string> relevantAirfields;
std::copy_if(
airfieldsProvidingServices.cbegin(),
airfieldsProvidingServices.cend(),
std::back_inserter(relevantAirfields),
[&renderFor](const std::string& airfield) -> bool {
return std::find(renderFor.cbegin(), renderFor.cend(), airfield) != renderFor.cend();
});

if (relevantAirfields.empty()) {
if (airfieldsProvidingServices.empty() && alwaysRenderFor.empty()) {
return;
}

// Combine the "always alerts" and the "service provision" alerts to get all relevant airfields
std::vector<std::string> relevantAirfields;
relevantAirfields.reserve(airfieldsProvidingServices.size() + alwaysRenderFor.size());
relevantAirfields.insert(
relevantAirfields.end(), airfieldsProvidingServices.begin(), airfieldsProvidingServices.end());
relevantAirfields.insert(relevantAirfields.end(), alwaysRenderFor.begin(), alwaysRenderFor.end());

this->missedApproaches->ForEach([this, &relevantAirfields, &radarScreen, &graphics](
const std::shared_ptr<class MissedApproach>& missed) {
// Only display for certain duration
Expand Down
19 changes: 19 additions & 0 deletions test/plugin/missedapproach/MissedApproachAudioAlertTest.cpp
Expand Up @@ -74,6 +74,15 @@ namespace UKControllerPluginTest::MissedApproach {
alert.Play(Create(true));
}

TEST_F(MissedApproachAudioAlertTest, ItPlaysAlertIfDestinationIsSetToAlwaysAlert)
{
this->options->SetServiceProvisions(ServiceType::Ground);
this->options->SetAirfields({"EGKK"});
EXPECT_CALL(mockWindows, PlayWave(MAKEINTRESOURCE(WAVE_MISSED_APPROACH))).Times(1);

alert.Play(Create(false));
}

TEST_F(MissedApproachAudioAlertTest, ItDoesntPlayAudioAlertIfTurnedOff)
{
this->options->SetAudioAlert(false);
Expand Down Expand Up @@ -101,6 +110,16 @@ namespace UKControllerPluginTest::MissedApproach {
alert.Play(Create(false));
}

TEST_F(MissedApproachAudioAlertTest, ItDoesntPlayAudioAlertIfIncorrectAirfieldIsOnAlwaysALert)
{
this->options->SetServiceProvisions(ServiceType::Ground);
this->options->SetAirfields({"EGLL"});

EXPECT_CALL(mockWindows, PlayWave(MAKEINTRESOURCE(WAVE_MISSED_APPROACH))).Times(0);

alert.Play(Create(false));
}

TEST_F(MissedApproachAudioAlertTest, ItDoesntPlayAudioAlertIfNoFlightplan)
{
ON_CALL(mockPlugin, GetFlightplanForCallsign("BAW123")).WillByDefault(testing::Return(nullptr));
Expand Down

0 comments on commit 5fe9fd7

Please sign in to comment.