diff --git a/src/PlugIn.cpp b/src/PlugIn.cpp index 39d91bc..9ede9b9 100644 --- a/src/PlugIn.cpp +++ b/src/PlugIn.cpp @@ -15,9 +15,12 @@ #include #include +#include #include #include +#include + #include "PlugIn.h" EXTERN_C IMAGE_DOS_HEADER __ImageBase; @@ -31,6 +34,8 @@ PlugIn::PlugIn() : PLUGIN_DEVELOPER, PLUGIN_COPYRIGHT), m_configuration() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + this->DisplayUserMessage(PLUGIN_NAME, "INFO", (std::string("Loaded ") + PLUGIN_NAME + " " + PLUGIN_VERSION).c_str(), true, true, false, false, false); /* get the dll-path */ @@ -53,9 +58,17 @@ PlugIn::PlugIn() : this->DisplayUserMessage(PLUGIN_NAME, "ERROR", ("AmanIdentity.txt:" + std::to_string(identFormat.errorLine()) + " - " + identFormat.errorMessage()).c_str(), true, true, true, true, true); return; } + + if (false == AircraftReporter::instance().initialize(this->m_configuration)) { + this->DisplayUserMessage(PLUGIN_NAME, "ERROR", "Unable to initialize the reporter-connection to the backend", true, true, true, true, true); + return; + } } -PlugIn::~PlugIn() noexcept { } +PlugIn::~PlugIn() noexcept { + AircraftReporter::instance().deinitialize(); + google::protobuf::ShutdownProtobufLibrary(); +} EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayName, bool needsRadarContent, bool geoReferenced, bool canBeSaved, bool canBeCreated) { @@ -71,6 +84,42 @@ EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayN return this->m_screen.get(); } +aman::Aircraft* PlugIn::generateAircraftMessage(const EuroScopePlugIn::CRadarTarget& target) { + if (false == target.IsValid() || false == target.GetCorrelatedFlightPlan().IsValid()) + return nullptr; + + auto flightPlan = target.GetCorrelatedFlightPlan(); + std::string callsign(target.GetCallsign()); + aman::Aircraft* retval = new aman::Aircraft(); + + /* fill all available information */ + retval->set_callsign(callsign); + if (3 <= callsign.length()) + retval->set_airline(callsign.substr(0, 3)); + retval->set_type(flightPlan.GetFlightPlanData().GetAircraftFPType()); + retval->set_wtc(std::to_string(flightPlan.GetFlightPlanData().GetAircraftWtc())); + /* TODO get recat */ + retval->set_enginecount(flightPlan.GetFlightPlanData().GetEngineNumber()); + + switch (flightPlan.GetFlightPlanData().GetEngineType()) { + case 'P': + case 'T': + retval->set_enginetype(aman::Aircraft_EngineType::Aircraft_EngineType_TURBOPROB); + break; + case 'E': + retval->set_enginetype(aman::Aircraft_EngineType::Aircraft_EngineType_ELECTRIC); + break; + case 'J': + retval->set_enginetype(aman::Aircraft_EngineType::Aircraft_EngineType_JET); + break; + default: + retval->set_enginetype(aman::Aircraft_EngineType::Aircraft_EngineType_UNKNOWN); + break; + } + + return retval; +} + void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) { /* ignore invalid targets */ if (false == radarTarget.IsValid()) @@ -90,15 +139,61 @@ void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarg if (nullptr == flightPlan.GetFlightPlanData().GetPlanType() || 'I' != *flightPlan.GetFlightPlanData().GetPlanType()) return; + /* filter invalid destinations */ + auto destination = std::string_view(flightPlan.GetFlightPlanData().GetDestination()); + if (4 != destination.length()) + return; + + /* TODO temporary filter */ + if ("EDDB" != destination) + return; + /* filter by distance to destination */ double distanceNM = flightPlan.GetDistanceToDestination(); - if (250.0 < distanceNM) + if (5.0 > distanceNM || 250.0 < distanceNM) return; /* filter by airborne identifier (assume a GS>50kn and a big distance to the origin) */ if (50 > radarTarget.GetGS() || 10.0 > flightPlan.GetDistanceFromOrigin()) return; - /* TODO generate protobuf message */ - /* TODO send aircraft update */ + /* generate protobuf message */ + aman::Aircraft* aircraft = this->generateAircraftMessage(radarTarget); + if (nullptr == aircraft) + return; + aman::Dynamics* dynamics = new aman::Dynamics(); + dynamics->set_altitude(radarTarget.GetPosition().GetFlightLevel()); + dynamics->set_groundspeed(radarTarget.GetGS()); + dynamics->set_verticalspeed(radarTarget.GetVerticalSpeed()); + aman::Coordinate* coordinate = new aman::Coordinate(); + coordinate->set_latitude(radarTarget.GetPosition().GetPosition().m_Latitude); + coordinate->set_longitude(radarTarget.GetPosition().GetPosition().m_Longitude); + + /* create the report */ + aman::AircraftReport report; + if (2 <= flightPlan.GetExtractedRoute().GetPointsNumber()) { + int lastIdx = flightPlan.GetExtractedRoute().GetPointsNumber() - 2; + + auto timeAtIAF = std::chrono::utc_clock::now(); + timeAtIAF += std::chrono::minutes(flightPlan.GetExtractedRoute().GetPointDistanceInMinutes(lastIdx)); + + std::stringstream stream; + stream << std::format("{0:%y%m%d%H%M}", timeAtIAF); + report.set_timeatiaf(stream.str()); + + report.set_initialapproachfix(std::string(flightPlan.GetExtractedRoute().GetPointName(lastIdx))); + } + report.set_destination(std::string(destination)); + report.set_allocated_aircraft(aircraft); + report.set_allocated_dynamics(dynamics); + report.set_allocated_position(coordinate); + + /* serialize the report */ + std::string serialized = report.SerializeAsString(); + zmq::message_t message(serialized.size()); + std::memcpy(message.data(), serialized.c_str(), serialized.size()); + + /* send the report */ + if (false == AircraftReporter::instance().send(message)) + this->DisplayUserMessage(PLUGIN_NAME, "ERROR", ("Unable to send a report for " + aircraft->callsign()).c_str(), true, true, true, true, true); } diff --git a/src/PlugIn.h b/src/PlugIn.h index 1d97521..f6b3e34 100644 --- a/src/PlugIn.h +++ b/src/PlugIn.h @@ -15,6 +15,7 @@ #pragma warning(pop) #include +#include #include "RadarScreen.h" @@ -35,6 +36,8 @@ namespace aman { enum class TagItemElement { }; + aman::Aircraft* generateAircraftMessage(const EuroScopePlugIn::CRadarTarget& target); + Communication m_configuration; std::shared_ptr m_screen;