Skip to content

Commit

Permalink
Merge pull request #13 from ECFMP/measure-applicability
Browse files Browse the repository at this point in the history
Measure applicability
  • Loading branch information
AndyTWF authored Aug 7, 2023
2 parents a8fdec6 + d421128 commit 8a6fe31
Show file tree
Hide file tree
Showing 71 changed files with 5,492 additions and 187 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
build:
name: Build
runs-on: windows-latest
runs-on: windows-2019
concurrency:
group: flow-sdk-build-${{ github.ref }}
cancel-in-progress: true
Expand Down
79 changes: 74 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,79 @@ A Software Development Kit (SDK) for the ECFMP Flow Control API

## Integrating With The SDK

Coming soon!
### Create a HTTP Client

## Building
Rather than ship with an opinionated viewpoint as to what you should use for HTTP requests, this SDK
provides an interface `HttpClient` that the HTTP client of your choice must implement.

### Create a logger

You can optionally pass the SDK a logging class that implements the `Logger` interface. This will allow you to log
messages from the SDK.

### Create an instance of the SDK

To create an instance of the SDK, you must use the `SDKFactory` class. This class will allow you to configure the SDK,
and
then create an instance of it.

```c++
#include "ECFMP/SDKFactory.h"
#include "ECFMP/SDK.h"

auto http = std::make_shared<MyHttpClient>();
auto logger = std::make_shared<MyLogger>();
auto ecfmp = ECFMP::Plugin::SdkFactory::Build()
.WithLogger(logger)
.WithHttpClient(std::move(http)).Instance();
```

### Add the SDK to EuroScopes timer event

The SDK needs to be called periodically to process events. To do this, you must add the call to the EuroScopes timer
event. This is necessary because EuroScope requires that calls to its internal classes are made from the plugin thread
(as opposed to something asynchronous.)

```c++
void MyPlugin::OnTimer(int time)
{
ecfmp.OnEuroscopeTimerTick();
}
```
### Register event handlers
You can register event handlers with the SDK. These event handlers will be called when the SDK processes an event.
These listeners must implement the `EventListener` interface.
```c++
auto eventListener = std::make_shared<MyListener<ECFMP::Plugin::FlowMeasureActivatedEvent>>();
ecfmp.EventBus().Subscribe<ECFMP::Plugin::FlowMeasureActivatedEvent>(eventListener);
```

## Testing Your Integration

You can test your integration by making use of the mocks provided by the SDK. These mocks will allow you to simulate
events that would be sent by the ECFMP SDK.

You can find the mocks in `include/mock`.

## Known Limitations

At the moment, the SDK has the following limitations:

- The SDK does not support Event Participation filters on Flow Measures. This is because EuroScope does not provide
the CID of the aircraft that is being filtered on, and thus a way around this needs to be devised.

## Development

### Building

This project builds using CMake. You can build using a command similar to below

`cmake -DCMAKE_BUILD_TYPE=<Release|Debug> -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_DEPENDS_USE_COMPILER=FALSE -G Ninja -Bbuild`

## Running Tests
### Running Tests

Tests can be run using the `ctest` command, from the build directory:

Expand All @@ -24,8 +88,13 @@ The SDK has the following design rationale.

### Event Driven

Similar to how EuroScope is event driven, so is this SDK. Integrations can register a series of event handlers with the SDK, which will pass on events, such as new Flow Measures for processing.
Similar to how EuroScope is event driven, so is this SDK. Integrations can register a series of event handlers with the
SDK, which will pass on events, such as new Flow Measures for processing.

The SDK itself is also event driven, and uses an internal event bus to handle events.

### Async

EuroScope is a single-threaded application when it comes to plugins, therefore, anything that may take a while (e.g. HTTP requests) will be done aysynchronously. The results of these operations will be deferred for when the EuroScope thread comes back around, as EuroScope sometimes doesn't like things interacting with it asynchronously.
EuroScope is a single-threaded application when it comes to plugins, therefore, anything that may take a while (e.g.
HTTP requests) will be done asynchronously. The results of these operations will be deferred for when the EuroScope
thread comes back around, as EuroScope sometimes doesn't like things interacting with it asynchronously.
3 changes: 2 additions & 1 deletion include/ECFMP/flowmeasure/AirportFilter.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "ChecksAircraftApplicability.h"

namespace ECFMP::FlowMeasure {

Expand All @@ -11,7 +12,7 @@ namespace ECFMP::FlowMeasure {
/**
* A filter that pertains to arrival or departure airports
*/
class AirportFilter
class AirportFilter : public ChecksAircraftApplicability
{
public:
virtual ~AirportFilter() = default;
Expand Down
19 changes: 19 additions & 0 deletions include/ECFMP/flowmeasure/ChecksAircraftApplicability.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

namespace ECFMP::Euroscope {
class EuroscopeAircraft;
}// namespace ECFMP::Euroscope

namespace ECFMP::FlowMeasure {
class ChecksAircraftApplicability
{
public:
virtual ~ChecksAircraftApplicability() = default;

/**
* Returns whether the given aircraft is applicable to this filter.
*/
[[nodiscard]] virtual auto ApplicableToAircraft(const Euroscope::EuroscopeAircraft& aircraft) const noexcept
-> bool = 0;
};
}// namespace ECFMP::FlowMeasure
3 changes: 2 additions & 1 deletion include/ECFMP/flowmeasure/EventFilter.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "ChecksAircraftApplicability.h"

namespace ECFMP::Event {
class Event;
Expand All @@ -19,7 +20,7 @@ namespace ECFMP::FlowMeasure {
/**
* A filter that pertains to participation in an event.
*/
class EventFilter
class EventFilter : public ChecksAircraftApplicability
{
public:
virtual ~EventFilter() = default;
Expand Down
13 changes: 13 additions & 0 deletions include/ECFMP/flowmeasure/FlowMeasure.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ namespace ECFMP {
}// namespace FlightInformationRegion
}// namespace ECFMP

namespace EuroScopePlugIn {
class CFlightPlan;
class CRadarTarget;
}// namespace EuroScopePlugIn

namespace ECFMP::FlowMeasure {
class FlowMeasureFilters;
class Measure;
Expand Down Expand Up @@ -115,5 +120,13 @@ namespace ECFMP::FlowMeasure {

// Information about the canonical nature of the flow measure
[[nodiscard]] virtual auto CanonicalInformation() const noexcept -> const CanonicalFlowMeasureInfo& = 0;

/**
* Returns true if the flow measure is applicable to the given aircraft. It will be applicable if all
* of the filters are applicable.
*/
[[nodiscard]] virtual auto ApplicableToAircraft(
const EuroScopePlugIn::CFlightPlan& flightplan, const EuroScopePlugIn::CRadarTarget& radarTarget
) const -> bool = 0;
};
}// namespace ECFMP::FlowMeasure
13 changes: 13 additions & 0 deletions include/ECFMP/flowmeasure/FlowMeasureFilters.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ namespace ECFMP::FlightInformationRegion {
class FlightInformationRegion;
}// namespace ECFMP::FlightInformationRegion

namespace EuroScopePlugIn {
class CFlightPlan;
class CRadarTarget;
}// namespace EuroScopePlugIn

namespace ECFMP::FlowMeasure {

class AirportFilter;
Expand All @@ -27,6 +32,14 @@ namespace ECFMP::FlowMeasure {
*/
[[nodiscard]] virtual auto ApplicableToAirport(const std::string& airfield) const noexcept -> bool = 0;

/**
* Returns true if the flow measure is applicable to the given aircraft. It will be applicable if all
* of the filters are applicable.
*/
[[nodiscard]] virtual auto ApplicableToAircraft(
const EuroScopePlugIn::CFlightPlan& flightplan, const EuroScopePlugIn::CRadarTarget& radarTarget
) const -> bool = 0;

/**
* Methods that allow for iteration of the filters.
*/
Expand Down
3 changes: 2 additions & 1 deletion include/ECFMP/flowmeasure/LevelRangeFilter.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "ChecksAircraftApplicability.h"

namespace ECFMP::FlowMeasure {

Expand All @@ -11,7 +12,7 @@ namespace ECFMP::FlowMeasure {
/**
* A filter that pertains to the cruising level of the aircraft.
*/
class LevelRangeFilter
class LevelRangeFilter : public ChecksAircraftApplicability
{
public:
virtual ~LevelRangeFilter() = default;
Expand Down
3 changes: 2 additions & 1 deletion include/ECFMP/flowmeasure/MultipleLevelFilter.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#pragma once
#include "ChecksAircraftApplicability.h"

namespace ECFMP::FlowMeasure {
/**
* A filter that pertains to the cruising level of the aircraft.
*/
class MultipleLevelFilter
class MultipleLevelFilter : public ChecksAircraftApplicability
{
public:
virtual ~MultipleLevelFilter() = default;
Expand Down
3 changes: 2 additions & 1 deletion include/ECFMP/flowmeasure/RangeToDestinationFilter.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#pragma once
#include "ChecksAircraftApplicability.h"

namespace ECFMP::FlowMeasure {
/**
* A filter that pertains to arrival or departure airports
*/
class RangeToDestinationFilter
class RangeToDestinationFilter : public ChecksAircraftApplicability
{
public:
virtual ~RangeToDestinationFilter() = default;
Expand Down
3 changes: 2 additions & 1 deletion include/ECFMP/flowmeasure/RouteFilter.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#pragma once
#include "ChecksAircraftApplicability.h"

namespace ECFMP::FlowMeasure {
/**
* A filter that pertains to aircraft on particular routes.
*/
class RouteFilter
class RouteFilter : public ChecksAircraftApplicability
{
public:
virtual ~RouteFilter() = default;
Expand Down
1 change: 1 addition & 0 deletions include/mock/AirportFilterMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace ECFMP::Mock::FlowMeasure {
MOCK_METHOD(const std::set<std::string>&, AirportStrings, (), (const, noexcept, override));
MOCK_METHOD(ECFMP::FlowMeasure::AirportFilterType, Type, (), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAirport, (const std::string&), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAircraft, (const Euroscope::EuroscopeAircraft&), (const, noexcept, override));
};

}// namespace ECFMP::Mock::FlowMeasure
1 change: 1 addition & 0 deletions include/mock/EventFilterMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace ECFMP::Mock::FlowMeasure {
MOCK_METHOD(const ECFMP::Event::Event&, Event, (), (const, noexcept, override));
MOCK_METHOD(ECFMP::FlowMeasure::EventParticipation, Participation, (), (const, noexcept, override));
MOCK_METHOD(bool, IsParticipating, (), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAircraft, (const Euroscope::EuroscopeAircraft&), (const, noexcept, override));
};

}// namespace ECFMP::Mock::FlowMeasure
4 changes: 4 additions & 0 deletions include/mock/FlowMeasureFiltersMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ namespace ECFMP::Mock::FlowMeasure {
{
public:
MOCK_METHOD(bool, ApplicableToAirport, (const std::string&), (const, noexcept, override));
MOCK_METHOD(
bool, ApplicableToAircraft, (const EuroScopePlugIn::CFlightPlan&, const EuroScopePlugIn::CRadarTarget&),
(const, noexcept, override)
);
MOCK_METHOD(
void, ForEachAirportFilter, (const std::function<void(const ECFMP::FlowMeasure::AirportFilter&)>&),
(const, noexcept, override)
Expand Down
4 changes: 4 additions & 0 deletions include/mock/FlowMeasureMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ namespace ECFMP::Mock::FlowMeasure {
(const ECFMP::FlightInformationRegion::FlightInformationRegion&), (const, noexcept, override)
);
MOCK_METHOD(bool, IsApplicableToFlightInformationRegion, (const std::string&), (const, noexcept, override));
MOCK_METHOD(
bool, ApplicableToAircraft, (const EuroScopePlugIn::CFlightPlan&, const EuroScopePlugIn::CRadarTarget&),
(const, override)
);
};

}// namespace ECFMP::Mock::FlowMeasure
1 change: 1 addition & 0 deletions include/mock/LevelRangeFilterMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace ECFMP::Mock::FlowMeasure {
MOCK_METHOD(int, Altitude, (), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAltitude, (int), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToLevel, (int), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAircraft, (const Euroscope::EuroscopeAircraft&), (const, noexcept, override));
};

}// namespace ECFMP::Mock::FlowMeasure
1 change: 1 addition & 0 deletions include/mock/MultipleLevelFilterMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace ECFMP::Mock::FlowMeasure {
MOCK_METHOD(std::vector<int>, Altitudes, (), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAltitude, (int), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToLevel, (int), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAircraft, (const Euroscope::EuroscopeAircraft&), (const, noexcept, override));
};

}// namespace ECFMP::Mock::FlowMeasure
14 changes: 14 additions & 0 deletions include/mock/RangeToDestinationFilterMock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#include "ECFMP/flowmeasure/RangeToDestinationFilter.h"
#include <gmock/gmock.h>

namespace ECFMP::Mock::FlowMeasure {
class RangeToDestinationFilterMock : public ECFMP::FlowMeasure::RangeToDestinationFilter
{
public:
MOCK_METHOD(
bool, ApplicableToAircraft, (const ECFMP::Euroscope::EuroscopeAircraft&), (const, noexcept, override)
);
MOCK_METHOD(int, Range, (), (const, noexcept, override));
};
}// namespace ECFMP::Mock::FlowMeasure
1 change: 1 addition & 0 deletions include/mock/RouteFilterMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace ECFMP::Mock::FlowMeasure {
{
public:
MOCK_METHOD(const std::set<std::string>&, RouteStrings, (), (const, noexcept, override));
MOCK_METHOD(bool, ApplicableToAircraft, (const Euroscope::EuroscopeAircraft&), (const, noexcept, override));
};

}// namespace ECFMP::Mock::FlowMeasure
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
#include "LevelRangeFilterMock.h"
#include "MeasureMock.h"
#include "MultipleLevelFilterMock.h"
#include "RangeToDestinationFilterMock.h"
#include "RouteFilterMock.h"
Binary file added lib/EuroScopePlugInDll.dll
Binary file not shown.
Binary file added lib/EuroScopePlugInDll.lib
Binary file not shown.
Loading

0 comments on commit 8a6fe31

Please sign in to comment.