Compare commits
10 Commits
d7c41d1941
...
e19e50b027
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e19e50b027 | ||
|
|
c5d5e332c8 | ||
|
|
7411955ede | ||
|
|
1873c68ab0 | ||
|
|
0a586f88c3 | ||
|
|
06271fde5b | ||
|
|
4e635514f1 | ||
|
|
d24c1ee1ce | ||
|
|
f54711f490 | ||
|
|
031c9faa97 |
@@ -38,6 +38,7 @@ namespace aman {
|
|||||||
std::vector<ArrivalWaypoint> m_arrivalRoute;
|
std::vector<ArrivalWaypoint> m_arrivalRoute;
|
||||||
Time m_timeToLose;
|
Time m_timeToLose;
|
||||||
UtcTime::Point m_waypointEstimatedTimeOfArrival;
|
UtcTime::Point m_waypointEstimatedTimeOfArrival;
|
||||||
|
bool m_resetFilter;
|
||||||
|
|
||||||
void updatePrediction(EuroScopePlugIn::CRadarTarget& target, const aman::AircraftSchedule& inbound);
|
void updatePrediction(EuroScopePlugIn::CRadarTarget& target, const aman::AircraftSchedule& inbound);
|
||||||
Velocity indicatedAirspeed(const Length& altitude) const noexcept;
|
Velocity indicatedAirspeed(const Length& altitude) const noexcept;
|
||||||
|
|||||||
140
src/PlugIn.cpp
140
src/PlugIn.cpp
@@ -58,6 +58,7 @@ PlugIn::PlugIn() :
|
|||||||
m_screen(),
|
m_screen(),
|
||||||
m_updateQueueLock(),
|
m_updateQueueLock(),
|
||||||
m_updateQueue(),
|
m_updateQueue(),
|
||||||
|
m_initialApproachFixes(),
|
||||||
m_inboundsQueueLock(),
|
m_inboundsQueueLock(),
|
||||||
m_inbounds(),
|
m_inbounds(),
|
||||||
m_forcedToBackendCallsigns(),
|
m_forcedToBackendCallsigns(),
|
||||||
@@ -111,6 +112,77 @@ PlugIn::~PlugIn() {
|
|||||||
google::protobuf::ShutdownProtobufLibrary();
|
google::protobuf::ShutdownProtobufLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlugIn::receiveConfiguration(const std::string& airport) {
|
||||||
|
/* set up the URL */
|
||||||
|
std::string url;
|
||||||
|
if (true == this->m_configuration.httpsProtocol)
|
||||||
|
url += "https://";
|
||||||
|
else
|
||||||
|
url += "http://";
|
||||||
|
url += this->m_configuration.address + ":" + std::to_string(this->m_configuration.portRestAPI) + "/aman/configuration/" + airport;
|
||||||
|
|
||||||
|
CURL* curl = curl_easy_init();
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, static_cast<long>(CURL_HTTP_VERSION_1_1));
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveCurl);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);
|
||||||
|
|
||||||
|
struct curl_slist* headers = nullptr;
|
||||||
|
headers = curl_slist_append(headers, "Accept: */*");
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
|
||||||
|
__receivedAmanData.clear();
|
||||||
|
|
||||||
|
result = curl_easy_perform(curl);
|
||||||
|
|
||||||
|
if (CURLE_OK != result) {
|
||||||
|
MessageBoxA(nullptr, "Unable to receive backend information", "AMAN-Error", MB_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* validate the json data */
|
||||||
|
Json::Value root;
|
||||||
|
Json::CharReaderBuilder builder;
|
||||||
|
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
|
||||||
|
if (false == reader->parse(__receivedAmanData.c_str(), __receivedAmanData.c_str() + __receivedAmanData.length(), &root, nullptr)) {
|
||||||
|
MessageBoxA(nullptr, "Received invalid backend data", "AMAN-Error", MB_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = root.begin(); root.end() != it; ++it) {
|
||||||
|
if ("iafs" == it.key().asString() && true == it->isArray()) {
|
||||||
|
auto iafArray = *it;
|
||||||
|
this->m_initialApproachFixes.insert({ airport, {} });
|
||||||
|
|
||||||
|
this->m_initialApproachFixes[airport].reserve(iafArray.size());
|
||||||
|
for (Json::Value::ArrayIndex i = 0; i < iafArray.size(); ++i) {
|
||||||
|
if (true == iafArray[i].isObject()) {
|
||||||
|
Angle latitude, longitude;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
for (auto cit = iafArray[i].begin(); iafArray[i].end() != cit; ++cit) {
|
||||||
|
if ("name" == cit.key().asString())
|
||||||
|
name = cit->asString();
|
||||||
|
else if ("lat" == cit.key().asString())
|
||||||
|
latitude = cit->asFloat() * degree;
|
||||||
|
else if ("lon" == cit.key().asString())
|
||||||
|
longitude = cit->asFloat() * degree;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_initialApproachFixes[airport].push_back({ name, GeoCoordinate(longitude, latitude) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PlugIn::validateBackendData() {
|
void PlugIn::validateBackendData() {
|
||||||
if (false == this->m_configuration.valid) {
|
if (false == this->m_configuration.valid) {
|
||||||
this->m_compatible = false;
|
this->m_compatible = false;
|
||||||
@@ -191,11 +263,16 @@ void PlugIn::validateBackendData() {
|
|||||||
|
|
||||||
std::lock_guard guard(this->m_updateQueueLock);
|
std::lock_guard guard(this->m_updateQueueLock);
|
||||||
this->m_updateQueue.clear();
|
this->m_updateQueue.clear();
|
||||||
for (const auto& airport : std::as_const(airports))
|
this->m_initialApproachFixes.clear();
|
||||||
|
|
||||||
|
for (const auto& airport : std::as_const(airports)) {
|
||||||
this->m_updateQueue.insert({ airport, {} });
|
this->m_updateQueue.insert({ airport, {} });
|
||||||
|
this->receiveConfiguration(airport);
|
||||||
|
}
|
||||||
|
|
||||||
this->m_compatible = true;
|
this->m_compatible = true;
|
||||||
|
|
||||||
this->DisplayUserMessage(PLUGIN_NAME, "INFO", "Reloaded AMAN-configuration", true, true, false, false, false);
|
this->DisplayUserMessage(PLUGIN_NAME, "INFO", "Loaded AMAN-configuration", true, true, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayName, bool needsRadarContent, bool geoReferenced,
|
EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayName, bool needsRadarContent, bool geoReferenced,
|
||||||
@@ -338,7 +415,7 @@ void PlugIn::generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarT
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* filter invalid destinations */
|
/* filter invalid destinations */
|
||||||
const auto destination = std::string_view(flightPlan.GetFlightPlanData().GetDestination());
|
const auto destination = std::string(flightPlan.GetFlightPlanData().GetDestination());
|
||||||
if (4 != destination.length())
|
if (4 != destination.length())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -384,39 +461,34 @@ void PlugIn::generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarT
|
|||||||
|
|
||||||
int iafRouteIndex = flightPlan.GetExtractedRoute().GetPointsNumber();
|
int iafRouteIndex = flightPlan.GetExtractedRoute().GetPointsNumber();
|
||||||
auto currentPosition = radarTarget.GetPosition().GetPosition();
|
auto currentPosition = radarTarget.GetPosition().GetPosition();
|
||||||
EuroScopePlugIn::CPosition iafPosition;
|
GeoCoordinate iafPosition;
|
||||||
std::string iafName;
|
std::string iafName;
|
||||||
|
|
||||||
for (auto element = this->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_STAR);
|
auto iafIt = this->m_initialApproachFixes.find(destination);
|
||||||
true == element.IsValid();
|
if (this->m_initialApproachFixes.cend() != iafIt) {
|
||||||
element = this->SectorFileElementSelectNext(element, EuroScopePlugIn::SECTOR_ELEMENT_STAR))
|
for (const auto& iaf : std::as_const(iafIt->second)) {
|
||||||
{
|
for (int i = 0; i < flightPlan.GetExtractedRoute().GetPointsNumber(); ++i) {
|
||||||
auto split = String::splitString(element.GetName(), " ");
|
if (flightPlan.GetExtractedRoute().GetPointName(i) == iaf.name) {
|
||||||
|
iafPosition = iaf.coordinate;
|
||||||
/* find the correct star */
|
iafName = iaf.name;
|
||||||
if (0 != split.size() && destination == gsl::at(split, 0)) {
|
break;
|
||||||
/* get the IAF */
|
|
||||||
EuroScopePlugIn::CPosition position;
|
|
||||||
if (true == element.GetPosition(&position, 0)) {
|
|
||||||
/* match the waypoints to get the name*/
|
|
||||||
for (int i = 0; i < flightPlan.GetExtractedRoute().GetPointsNumber(); ++i) {
|
|
||||||
if (1.0f >= flightPlan.GetExtractedRoute().GetPointPosition(i).DistanceTo(position)) {
|
|
||||||
iafPosition = flightPlan.GetExtractedRoute().GetPointPosition(i);
|
|
||||||
iafName = flightPlan.GetExtractedRoute().GetPointName(i);
|
|
||||||
report->set_initialapproachfix(iafName);
|
|
||||||
iafRouteIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != iafName.length())
|
if (0 == iafName.length() && flightPlan.GetControllerAssignedData().GetDirectToPointName() == iaf.name) {
|
||||||
break;
|
iafPosition = iaf.coordinate;
|
||||||
|
iafName = iaf.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != iafName.length())
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != iafName.length()) {
|
if (0 != iafName.length()) {
|
||||||
const std::string_view direct(flightPlan.GetControllerAssignedData().GetDirectToPointName());
|
report->set_initialapproachfix(iafName);
|
||||||
|
|
||||||
|
std::string_view direct(flightPlan.GetControllerAssignedData().GetDirectToPointName());
|
||||||
bool directBehindIAF = false;
|
bool directBehindIAF = false;
|
||||||
|
|
||||||
if (0 != direct.length()) {
|
if (0 != direct.length()) {
|
||||||
@@ -428,18 +500,21 @@ void PlugIn::generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EuroScopePlugIn::CPosition iaf;
|
||||||
|
iaf.m_Longitude = iafPosition.longitude().convert(degree);
|
||||||
|
iaf.m_Latitude = iafPosition.latitude().convert(degree);
|
||||||
|
|
||||||
if (true == directBehindIAF) {
|
if (true == directBehindIAF) {
|
||||||
PlugIn::distanceToPredictedIaf(radarTarget, flightPlan, iafPosition, report);
|
PlugIn::distanceToPredictedIaf(radarTarget, flightPlan, iaf, report);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const GeoCoordinate iaf(static_cast<float>(iafPosition.m_Longitude) * degree, static_cast<float>(iafPosition.m_Latitude) * degree);
|
|
||||||
const Velocity groundspeed = static_cast<float>(radarTarget.GetGS()) * knot;
|
const Velocity groundspeed = static_cast<float>(radarTarget.GetGS()) * knot;
|
||||||
Length distanceToIaf;
|
Length distanceToIaf;
|
||||||
const auto idx = Inbound::matchToPredictedPath(flightPlan.GetPositionPredictions(), iaf, groundspeed, distanceToIaf);
|
const auto idx = Inbound::matchToPredictedPath(flightPlan.GetPositionPredictions(), iafPosition, groundspeed, distanceToIaf);
|
||||||
|
|
||||||
/* not inbound the IAF -> check if we passed it */
|
/* not inbound the IAF -> check if we passed it */
|
||||||
if (flightPlan.GetPositionPredictions().GetPointsNumber() <= idx)
|
if (flightPlan.GetPositionPredictions().GetPointsNumber() <= idx)
|
||||||
PlugIn::distanceToPredictedIaf(radarTarget, flightPlan, iafPosition, report);
|
PlugIn::distanceToPredictedIaf(radarTarget, flightPlan, iaf, report);
|
||||||
else
|
else
|
||||||
report->set_distancetoiaf(static_cast<int>(std::round(distanceToIaf.convert(nauticmile))));
|
report->set_distancetoiaf(static_cast<int>(std::round(distanceToIaf.convert(nauticmile))));
|
||||||
}
|
}
|
||||||
@@ -809,7 +884,6 @@ void PlugIn::updateSequence(std::shared_ptr<aman::AircraftSequence>& sequence) {
|
|||||||
|
|
||||||
if (false == found) {
|
if (false == found) {
|
||||||
/* delete the forced runway selection */
|
/* delete the forced runway selection */
|
||||||
std::lock_guard guard(this->m_updateQueueLock);
|
|
||||||
auto selected = this->m_selectedRunway.find(it->first);
|
auto selected = this->m_selectedRunway.find(it->first);
|
||||||
if (this->m_selectedRunway.end() != selected)
|
if (this->m_selectedRunway.end() != selected)
|
||||||
this->m_selectedRunway.erase(selected);
|
this->m_selectedRunway.erase(selected);
|
||||||
|
|||||||
30
src/PlugIn.h
30
src/PlugIn.h
@@ -47,6 +47,10 @@ namespace aman {
|
|||||||
std::vector<std::string> arrivalRunways;
|
std::vector<std::string> arrivalRunways;
|
||||||
std::list<std::string> inboundUpdates;
|
std::list<std::string> inboundUpdates;
|
||||||
};
|
};
|
||||||
|
struct InitialApproachFix {
|
||||||
|
std::string name;
|
||||||
|
GeoCoordinate coordinate;
|
||||||
|
};
|
||||||
|
|
||||||
enum class TagItemElement {
|
enum class TagItemElement {
|
||||||
EstimatedTimeOfArrival = 0,
|
EstimatedTimeOfArrival = 0,
|
||||||
@@ -56,6 +60,7 @@ namespace aman {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void validateBackendData();
|
void validateBackendData();
|
||||||
|
void receiveConfiguration(const std::string& airport);
|
||||||
aman::Aircraft* generateAircraftMessage(const EuroScopePlugIn::CRadarTarget& target) const;
|
aman::Aircraft* generateAircraftMessage(const EuroScopePlugIn::CRadarTarget& target) const;
|
||||||
void generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarTarget, aman::AircraftReport* report);
|
void generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarTarget, aman::AircraftReport* report);
|
||||||
void addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget);
|
void addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget);
|
||||||
@@ -64,18 +69,19 @@ namespace aman {
|
|||||||
static void distanceToPredictedIaf(const EuroScopePlugIn::CRadarTarget& radarTarget, const EuroScopePlugIn::CFlightPlan& flightPlan,
|
static void distanceToPredictedIaf(const EuroScopePlugIn::CRadarTarget& radarTarget, const EuroScopePlugIn::CFlightPlan& flightPlan,
|
||||||
const EuroScopePlugIn::CPosition& iafPosition, aman::AircraftReport* report);
|
const EuroScopePlugIn::CPosition& iafPosition, aman::AircraftReport* report);
|
||||||
|
|
||||||
Communication m_configuration;
|
Communication m_configuration;
|
||||||
std::shared_ptr<RadarScreen> m_screen;
|
std::shared_ptr<RadarScreen> m_screen;
|
||||||
std::mutex m_updateQueueLock;
|
std::mutex m_updateQueueLock;
|
||||||
std::map<std::string, AirportData> m_updateQueue;
|
std::map<std::string, AirportData> m_updateQueue;
|
||||||
std::mutex m_inboundsQueueLock;
|
std::map<std::string, std::vector<InitialApproachFix>> m_initialApproachFixes;
|
||||||
std::map<std::string, Inbound> m_inbounds;
|
std::mutex m_inboundsQueueLock;
|
||||||
std::map<std::string, std::string> m_selectedRunway;
|
std::map<std::string, Inbound> m_inbounds;
|
||||||
std::list<std::string> m_forcedToBackendCallsigns;
|
std::map<std::string, std::string> m_selectedRunway;
|
||||||
bool m_compatible;
|
std::list<std::string> m_forcedToBackendCallsigns;
|
||||||
bool m_connectedToNetwork;
|
bool m_compatible;
|
||||||
bool m_sweatboxValid;
|
bool m_connectedToNetwork;
|
||||||
bool m_playbackValid;
|
bool m_sweatboxValid;
|
||||||
|
bool m_playbackValid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|||||||
Submodule src/com/protobuf updated: 5c00b8c4fc...893e012b3f
@@ -37,9 +37,12 @@ Inbound::Inbound(EuroScopePlugIn::CRadarTarget& target, const aman::AircraftSche
|
|||||||
m_runway(inbound.arrivalrunway()),
|
m_runway(inbound.arrivalrunway()),
|
||||||
m_nextStarWaypoint(0),
|
m_nextStarWaypoint(0),
|
||||||
m_arrivalRoute(),
|
m_arrivalRoute(),
|
||||||
m_timeToLose() {
|
m_timeToLose(),
|
||||||
|
m_waypointEstimatedTimeOfArrival(),
|
||||||
|
m_resetFilter(true) {
|
||||||
this->createWindTables(wind);
|
this->createWindTables(wind);
|
||||||
this->updatePrediction(target, inbound);
|
this->updatePrediction(target, inbound);
|
||||||
|
this->update(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inbound::createWindTables(const google::protobuf::RepeatedPtrField<aman::WindData>& wind) {
|
void Inbound::createWindTables(const google::protobuf::RepeatedPtrField<aman::WindData>& wind) {
|
||||||
@@ -331,7 +334,15 @@ void Inbound::predictETA(const EuroScopePlugIn::CRadarTarget& target, const Euro
|
|||||||
this->m_waypointEstimatedTimeOfArrival = UtcTime::currentUtc() + std::chrono::seconds(static_cast<long long>(flightTime.convert(second)));
|
this->m_waypointEstimatedTimeOfArrival = UtcTime::currentUtc() + std::chrono::seconds(static_cast<long long>(flightTime.convert(second)));
|
||||||
const auto delta = std::chrono::duration_cast<std::chrono::seconds>(destination.plannedArrivalTime() - UtcTime::currentUtc());
|
const auto delta = std::chrono::duration_cast<std::chrono::seconds>(destination.plannedArrivalTime() - UtcTime::currentUtc());
|
||||||
const auto plannedFlightTime = static_cast<float>(delta.count()) * second;
|
const auto plannedFlightTime = static_cast<float>(delta.count()) * second;
|
||||||
this->m_timeToLose = plannedFlightTime - flightTime;
|
const auto timeToLose = plannedFlightTime - flightTime;
|
||||||
|
|
||||||
|
if (true == this->m_resetFilter) {
|
||||||
|
this->m_timeToLose = timeToLose;
|
||||||
|
this->m_resetFilter = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->m_timeToLose = 0.9f * this->m_timeToLose + 0.1f * timeToLose;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inbound::update(EuroScopePlugIn::CRadarTarget& target) {
|
void Inbound::update(EuroScopePlugIn::CRadarTarget& target) {
|
||||||
@@ -345,8 +356,10 @@ void Inbound::update(EuroScopePlugIn::CRadarTarget& target) {
|
|||||||
if (this->m_nextStarWaypoint < this->m_arrivalRoute.size()) {
|
if (this->m_nextStarWaypoint < this->m_arrivalRoute.size()) {
|
||||||
const auto maxDistance = this->m_groundSpeed * 60_s;
|
const auto maxDistance = this->m_groundSpeed * 60_s;
|
||||||
|
|
||||||
if (maxDistance > gsl::at(this->m_arrivalRoute, this->m_nextStarWaypoint).position().distanceTo(__convert(target.GetPosition().GetPosition())))
|
if (maxDistance > gsl::at(this->m_arrivalRoute, this->m_nextStarWaypoint).position().distanceTo(__convert(target.GetPosition().GetPosition()))) {
|
||||||
this->m_nextStarWaypoint += 1;
|
this->m_nextStarWaypoint += 1;
|
||||||
|
this->m_resetFilter = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->predictETA(target, target.GetCorrelatedFlightPlan().GetPositionPredictions());
|
this->predictETA(target, target.GetCorrelatedFlightPlan().GetPositionPredictions());
|
||||||
@@ -355,6 +368,8 @@ void Inbound::update(EuroScopePlugIn::CRadarTarget& target) {
|
|||||||
void Inbound::directTo(EuroScopePlugIn::CRadarTarget& radarTarget, const std::string& waypoint) {
|
void Inbound::directTo(EuroScopePlugIn::CRadarTarget& radarTarget, const std::string& waypoint) {
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
|
|
||||||
|
this->m_resetFilter = true;
|
||||||
|
|
||||||
for (const auto& arrivalPoint : std::as_const(this->m_arrivalRoute)) {
|
for (const auto& arrivalPoint : std::as_const(this->m_arrivalRoute)) {
|
||||||
if (arrivalPoint.name() == waypoint) {
|
if (arrivalPoint.name() == waypoint) {
|
||||||
this->m_nextStarWaypoint = i;
|
this->m_nextStarWaypoint = i;
|
||||||
|
|||||||
Reference in New Issue
Block a user