update the inbound queue lock

This commit is contained in:
Sven Czarnian
2021-11-25 22:28:32 +01:00
parent 1936b3649b
commit eb521fca8b
2 changed files with 188 additions and 9 deletions

View File

@@ -53,6 +53,8 @@ PlugIn::PlugIn() :
m_screen(), m_screen(),
m_updateQueueLock(), m_updateQueueLock(),
m_updateQueue(), m_updateQueue(),
m_inboundsQueueLock(),
m_inbounds(),
m_forcedToBackendCallsigns(), m_forcedToBackendCallsigns(),
m_compatible(false) { m_compatible(false) {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -391,6 +393,69 @@ bool PlugIn::OnCompileCommand(const char* cmdline) {
return false; 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) { void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RECT area) {
std::ignore = itemString; std::ignore = itemString;
std::ignore = pt; std::ignore = pt;
@@ -423,11 +488,7 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE
} }
} }
void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) { void PlugIn::addUpdateQueue(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;
std::lock_guard guard(this->m_updateQueueLock); std::lock_guard guard(this->m_updateQueueLock);
auto forcedIt = std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), radarTarget.GetCallsign()); 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()); 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) { void PlugIn::OnFlightPlanDisconnect(EuroScopePlugIn::CFlightPlan flightPlan) {
std::string callsign(flightPlan.GetCorrelatedRadarTarget().GetCallsign()); 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); auto it = std::find(this->m_forcedToBackendCallsigns.begin(), this->m_forcedToBackendCallsigns.end(), callsign);
if (this->m_forcedToBackendCallsigns.end() != it) if (this->m_forcedToBackendCallsigns.end() != it)
this->m_forcedToBackendCallsigns.erase(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) { void PlugIn::OnTimer(int counter) {
@@ -472,16 +623,17 @@ void PlugIn::OnTimer(int counter) {
} }
} }
/* send the report */
if (true == inserted) { if (true == inserted) {
/* send the report and request the current sequence */
auto sequence = Backend::instance().update(update); 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); 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(); airport.second.clear();
} }
this->m_updateQueue.clear();
this->m_updateQueueLock.unlock(); this->m_updateQueueLock.unlock();
} }

View File

@@ -15,6 +15,7 @@
#pragma warning(pop) #pragma warning(pop)
#include <aman/types/Communication.h> #include <aman/types/Communication.h>
#include <aman/types/Inbound.h>
#pragma warning(push, 0) #pragma warning(push, 0)
#include <protobuf/BaseTypes.pb.h> #include <protobuf/BaseTypes.pb.h>
@@ -46,11 +47,17 @@ namespace aman {
void validateBackendData(); void validateBackendData();
aman::Aircraft* generateAircraftMessage(EuroScopePlugIn::CRadarTarget& target); aman::Aircraft* generateAircraftMessage(EuroScopePlugIn::CRadarTarget& target);
void generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarTarget, aman::AircraftReport* report); 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; 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, std::list<std::string>> m_updateQueue; 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; std::list<std::string> m_forcedToBackendCallsigns;
bool m_compatible; bool m_compatible;
@@ -94,11 +101,31 @@ namespace aman {
* @param[in] area The clicked area * @param[in] area The clicked area
*/ */
void OnFunctionCall(int functionId, const char* itemString, POINT pt, RECT area) override; 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 * @brief Called every second
* @param[in] counter The counter that indicates the seconds * @param[in] counter The counter that indicates the seconds
*/ */
void OnTimer(int counter) override; 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 * @brief Called as soon as a radar target position is updated
* @param[in] radarTarget The updated radar target * @param[in] radarTarget The updated radar target