|
@@ -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();
|
|
|
}
|