Browse Source

update the inbound queue lock

Sven Czarnian 3 years ago
parent
commit
eb521fca8b
2 changed files with 188 additions and 9 deletions
  1. 161 9
      src/PlugIn.cpp
  2. 27 0
      src/PlugIn.h

+ 161 - 9
src/PlugIn.cpp

@@ -53,6 +53,8 @@ PlugIn::PlugIn() :
         m_screen(),
         m_updateQueueLock(),
         m_updateQueue(),
+        m_inboundsQueueLock(),
+        m_inbounds(),
         m_forcedToBackendCallsigns(),
         m_compatible(false) {
     GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -391,6 +393,69 @@ bool PlugIn::OnCompileCommand(const char* cmdline) {
     return false;
 }
 
+void PlugIn::OnGetTagItem(EuroScopePlugIn::CFlightPlan flightPlan, EuroScopePlugIn::CRadarTarget radarTarget,
+                          int itemCode, int tagData, char itemString[16], int* colorCode, COLORREF* rgb,
+                          double* fontSize) {
+    std::ignore = tagData;
+    std::ignore = rgb;
+    std::ignore = fontSize;
+
+    std::string callsign(radarTarget.GetCallsign());
+    std::string destination(flightPlan.GetFlightPlanData().GetDestination());
+#pragma warning(disable: 4244)
+    std::transform(destination.begin(), destination.end(), destination.begin(), ::toupper);
+#pragma warning(default: 4244)
+
+    bool planExpected, forced;
+
+    this->m_updateQueueLock.lock();
+
+    /* check if the inbound is forced */
+    auto cIt = std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), callsign);
+    forced = this->m_forcedToBackendCallsigns.cend() != cIt;
+
+    /* check if the inbound is expected to be planned */
+    planExpected = this->m_updateQueue.cend() != this->m_updateQueue.find(destination);
+
+    this->m_updateQueueLock.unlock();
+
+    if (TagItemElement::DeltaTime == static_cast<TagItemElement>(itemCode)) {
+        if (true == this->m_compatible) {
+            std::lock_guard guard(this->m_inboundsQueueLock);
+            auto it = this->m_inbounds.find(callsign);
+
+            /* inbound expected, but not available */
+            if (this->m_inbounds.cend() == it && (true == forced || true == planExpected)) {
+                std::strcpy(itemString, "??:??");
+                *colorCode = EuroScopePlugIn::TAG_COLOR_INFORMATION;
+            }
+            /* inbound is available */
+            else if (this->m_inbounds.cend() != it) {
+                const auto ttl = static_cast<int>(std::roundf(it->second.timeToLose().convert(second)));
+                const auto minutes = ttl / 60;
+                const auto seconds = std::abs(ttl) % 60;
+
+                std::stringstream stream;
+                stream << std::setw(2) << std::setfill('0') << minutes << ":"
+                       << std::setw(2) << std::setfill('0') << seconds;
+                std::strcpy(itemString, stream.str().c_str());
+
+                if (false == it->second.fixedPlan())
+                    *colorCode = EuroScopePlugIn::TAG_COLOR_INFORMATION;
+                else
+                    *colorCode = EuroScopePlugIn::TAG_COLOR_DEFAULT;
+            }
+            else {
+                itemString[0] = '\0';
+            }
+        }
+        else {
+            std::strcpy(itemString, "N/A");
+            *colorCode = EuroScopePlugIn::TAG_COLOR_DEFAULT;
+        }
+    }
+}
+
 void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RECT area) {
     std::ignore = itemString;
     std::ignore = pt;
@@ -423,11 +488,7 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE
     }
 }
 
-void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) {
-    /* do nothing if the reporter is not initialized and ignore invalid targets */
-    if (false == this->m_compatible || false == Backend::instance().initialized() || false == radarTarget.IsValid())
-        return;
-
+void PlugIn::addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget) {
     std::lock_guard guard(this->m_updateQueueLock);
 
     auto forcedIt = std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), radarTarget.GetCallsign());
@@ -444,13 +505,103 @@ void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarg
         it->second.push_back(radarTarget.GetCallsign());
 }
 
+void PlugIn::updateInbound(EuroScopePlugIn::CRadarTarget& radarTarget) {
+    std::lock_guard guard(this->m_inboundsQueueLock);
+    auto it = this->m_inbounds.find(radarTarget.GetCallsign());
+    if (this->m_inbounds.end() != it)
+        it->second.update(radarTarget);
+}
+
+void PlugIn::updateInbound(EuroScopePlugIn::CFlightPlan& plan) {
+    std::lock_guard guard(this->m_inboundsQueueLock);
+    auto it = this->m_inbounds.find(plan.GetCorrelatedRadarTarget().GetCallsign());
+    if (this->m_inbounds.end() != it)
+        it->second.update(plan);
+}
+
+void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) {
+    /* do nothing if the reporter is not initialized and ignore invalid targets */
+    if (false == this->m_compatible || false == Backend::instance().initialized() || false == radarTarget.IsValid())
+        return;
+
+    this->addUpdateQueue(radarTarget);
+    this->updateInbound(radarTarget);
+}
+
+void PlugIn::OnFlightPlanControllerAssignedDataUpdate(EuroScopePlugIn::CFlightPlan flightPlan, int type) {
+    /* handle only relevant changes */
+    if (EuroScopePlugIn::CTR_DATA_TYPE_HEADING != type && EuroScopePlugIn::CTR_DATA_TYPE_DIRECT_TO != type)
+        return;
+
+    if (false == flightPlan.GetCorrelatedRadarTarget().IsValid())
+        return;
+
+    this->updateInbound(flightPlan);
+}
+
 void PlugIn::OnFlightPlanDisconnect(EuroScopePlugIn::CFlightPlan flightPlan) {
     std::string callsign(flightPlan.GetCorrelatedRadarTarget().GetCallsign());
-    std::lock_guard guard(this->m_updateQueueLock);
 
+    this->m_updateQueueLock.lock();
     auto it = std::find(this->m_forcedToBackendCallsigns.begin(), this->m_forcedToBackendCallsigns.end(), callsign);
     if (this->m_forcedToBackendCallsigns.end() != it)
         this->m_forcedToBackendCallsigns.erase(it);
+    this->m_updateQueueLock.unlock();
+
+    this->m_inboundsQueueLock.lock();
+    auto inIt = this->m_inbounds.find(flightPlan.GetCorrelatedRadarTarget().GetCallsign());
+    if (this->m_inbounds.end() != inIt)
+        this->m_inbounds.erase(inIt);
+    this->m_inboundsQueueLock.unlock();
+}
+
+void PlugIn::updateSequence(std::shared_ptr<aman::AircraftSequence>& sequence) {
+    /* cleanup the inbound list */
+    this->m_inboundsQueueLock.lock();
+    for (auto it = this->m_inbounds.begin(); this->m_inbounds.end() != it;) {
+        bool found = false;
+
+        /* check if the inbound is part of the server */
+        for (auto i = 0; i < sequence->sequence_size(); ++i) {
+            if (sequence->sequence(i).callsign() == it->first) {
+                found = true;
+                break;
+            }
+        }
+
+        if (false == found)
+            it = this->m_inbounds.erase(it);
+        else
+            ++it;
+    }
+    this->m_inboundsQueueLock.unlock();
+
+    /* update the inbound list */
+    for (auto i = 0; i < sequence->sequence_size(); ++i) {
+        const auto& inbound = sequence->sequence(i);
+        EuroScopePlugIn::CRadarTarget target;
+        bool found = false;
+
+        for (target = this->RadarTargetSelectFirst(); true == target.IsValid(); target = this->RadarTargetSelectNext(target)) {
+            if (target.GetCallsign() == inbound.callsign()) {
+                found = true;
+                break;
+            }
+        }
+
+        if (true == found) {
+            auto msg = inbound.callsign() + ": PTA: " + inbound.waypoints(inbound.waypoints_size() - 1).pta();
+            this->DisplayUserMessage("Test", "Test", msg.c_str(), true, false, false, false, false);
+
+            this->m_inboundsQueueLock.lock();
+            auto it = this->m_inbounds.find(inbound.callsign());
+            if (this->m_inbounds.end() != it)
+                it->second.update(target, inbound, sequence->winddata());
+            else
+                this->m_inbounds.insert({ inbound.callsign(), Inbound(target, inbound, sequence->winddata()) });
+            this->m_inboundsQueueLock.unlock();
+        }
+    }
 }
 
 void PlugIn::OnTimer(int counter) {
@@ -472,16 +623,17 @@ void PlugIn::OnTimer(int counter) {
             }
         }
 
-        /* send the report */
         if (true == inserted) {
+            /* send the report and request the current sequence */
             auto sequence = Backend::instance().update(update);
-            if (nullptr != sequence)
+            if (nullptr == sequence)
                 this->DisplayUserMessage(PLUGIN_NAME, "ERROR", "Unable to send a new aircraft report update", true, true, true, true, true);
+            else
+                this->updateSequence(sequence);
         }
 
         airport.second.clear();
     }
 
-    this->m_updateQueue.clear();
     this->m_updateQueueLock.unlock();
 }

+ 27 - 0
src/PlugIn.h

@@ -15,6 +15,7 @@
 #pragma warning(pop)
 
 #include <aman/types/Communication.h>
+#include <aman/types/Inbound.h>
 
 #pragma warning(push, 0)
 #include <protobuf/BaseTypes.pb.h>
@@ -46,11 +47,17 @@ namespace aman {
         void validateBackendData();
         aman::Aircraft* generateAircraftMessage(EuroScopePlugIn::CRadarTarget& target);
         void generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarTarget, aman::AircraftReport* report);
+        void addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget);
+        void updateInbound(EuroScopePlugIn::CRadarTarget& radarTarget);
+        void updateInbound(EuroScopePlugIn::CFlightPlan& plan);
+        void updateSequence(std::shared_ptr<aman::AircraftSequence>& sequence);
 
         Communication                                 m_configuration;
         std::shared_ptr<RadarScreen>                  m_screen;
         std::mutex                                    m_updateQueueLock;
         std::map<std::string, std::list<std::string>> m_updateQueue;
+        std::mutex                                    m_inboundsQueueLock;
+        std::map<std::string, Inbound>                m_inbounds;
         std::list<std::string>                        m_forcedToBackendCallsigns;
         bool                                          m_compatible;
 
@@ -94,11 +101,31 @@ namespace aman {
          * @param[in] area The clicked area
          */
         void OnFunctionCall(int functionId, const char* itemString, POINT pt, RECT area) override;
+        /**
+         * @brief Called as soon as a tag entry needs to be updated
+         * @param[in] flightPlan The requested flight plan
+         * @param[in] radarTarget The corresponding RADAR target
+         * @param[in] itemCode The requested item
+         * @param[in] tagData The requested tag data
+         * @param[in] itemString The buffer to store the data
+         * @param[in] colorCode The color code of the entry
+         * @param[in] rgb The colorization of the entry
+         * @param[in] fontSize The size of the text
+         */
+        void OnGetTagItem(EuroScopePlugIn::CFlightPlan flightPlan, EuroScopePlugIn::CRadarTarget radarTarget,
+                          int itemCode, int tagData, char itemString[16], int* colorCode, COLORREF* rgb,
+                          double* fontSize) override;
         /**
          * @brief Called every second
          * @param[in] counter The counter that indicates the seconds
          */
         void OnTimer(int counter) override;
+        /**
+         * @brief Called as soon as a controller updated the flight plan
+         * @param[in] flightPlan The updated flight plan
+         * @param[in] type The changed information
+         */
+        void OnFlightPlanControllerAssignedDataUpdate(EuroScopePlugIn::CFlightPlan flightPlan, int type) override;
         /**
           * @brief Called as soon as a radar target position is updated
           * @param[in] radarTarget The updated radar target