diff --git a/appveyor.yml b/.appveyor.yml similarity index 91% rename from appveyor.yml rename to .appveyor.yml index 861a6c21e..22a306fcf 100644 --- a/appveyor.yml +++ b/.appveyor.yml @@ -9,17 +9,7 @@ #---------------------------------# # version format -version: 1.5.{build} - -# branches to build -branches: - # whitelist - only: - - master - - # blacklist - except: - - gh-pages +version: 1.6.{build} # Maximum number of concurrent jobs for the project max_jobs: 1 @@ -29,7 +19,7 @@ max_jobs: 1 #---------------------------------# # Build worker image (VM template) -os: Visual Studio 2019 +os: Visual Studio 2022 #---------------------------------# # build configuration # @@ -59,3 +49,5 @@ after_build: artifacts: - path: vSMR-nightly.zip + + diff --git a/vSMR/CPDLCSettingsDialog.cpp b/vSMR/CPDLCSettingsDialog.cpp index d06970911..4348f9027 100644 --- a/vSMR/CPDLCSettingsDialog.cpp +++ b/vSMR/CPDLCSettingsDialog.cpp @@ -15,6 +15,7 @@ CCPDLCSettingsDialog::CCPDLCSettingsDialog(CWnd* pParent /*=NULL*/) , m_Logon(_T("EGKK")) , m_Password(_T("PASSWORD")) , m_Sound(1) + , m_AutoLogon(0) { } @@ -29,6 +30,7 @@ void CCPDLCSettingsDialog::DoDataExchange(CDataExchange* pDX) DDX_Text(pDX, IDC_LOGON, m_Logon); DDX_Text(pDX, IDC_PASSWORD, m_Password); DDX_Check(pDX, IDC_SOUND, m_Sound); + DDX_Check(pDX, IDC_AUTOLOGON, m_AutoLogon); } diff --git a/vSMR/CPDLCSettingsDialog.hpp b/vSMR/CPDLCSettingsDialog.hpp index 44fd6b507..89037baf4 100644 --- a/vSMR/CPDLCSettingsDialog.hpp +++ b/vSMR/CPDLCSettingsDialog.hpp @@ -15,6 +15,7 @@ class CCPDLCSettingsDialog : public CDialogEx CString m_Logon; CString m_Password; int m_Sound; + int m_AutoLogon; // Dialog Data enum { IDD = IDD_DIALOG2 }; diff --git a/vSMR/SMRPlugin.cpp b/vSMR/SMRPlugin.cpp index d624d549a..3e2e1a3b0 100644 --- a/vSMR/SMRPlugin.cpp +++ b/vSMR/SMRPlugin.cpp @@ -11,13 +11,17 @@ bool FailedToConnectMessage = false; string logonCode = ""; string logonCallsign = "EGKK"; -HttpHelper * httpHelper = NULL; +HttpHelper *httpHelper = NULL; bool BLINK = false; bool PlaySoundClr = false; -struct DatalinkPacket { +// bool AutoConnect = false; +bool isConnecting = false; + +struct DatalinkPacket +{ string callsign; string destination; string sid; @@ -34,7 +38,8 @@ DatalinkPacket DatalinkToSend; string baseUrlDatalink = "http://www.hoppie.nl/acars/system/connect.html"; -struct AcarsMessage { +struct AcarsMessage +{ string from; string type; string message; @@ -53,6 +58,12 @@ string ttype; int messageId = 0; +// Retry Timer +int loginRetryCount = 0; +const int maxLoginRetries = 5; +const int loginRetryDelaySec = 120; // 2 minutes not to spam Hoppie server +time_t nextLoginRetryTime = 0; + clock_t timer; string myfrequency; @@ -64,9 +75,10 @@ bool startThreadvStrips = true; using namespace SMRPluginSharedData; char recv_buf[1024]; -vector RadarScreensOpened; +vector RadarScreensOpened; -void datalinkLogin(void * arg) { +void datalinkLogin(void *arg) +{ string raw; string url = baseUrlDatalink; url += "?logon="; @@ -76,16 +88,33 @@ void datalinkLogin(void * arg) { url += "&to=SERVER&type=PING"; raw.assign(httpHelper->downloadStringFromURL(url)); - if (startsWith("ok", raw.c_str())) { + if (startsWith("ok", raw.c_str())) + { HoppieConnected = true; ConnectionMessage = true; + loginRetryCount = 0; + isConnecting = false; } - else { + else + { FailedToConnectMessage = true; + loginRetryCount++; + if (loginRetryCount <= maxLoginRetries) + { + // Set next retry time + nextLoginRetryTime = time(NULL) + loginRetryDelaySec; + } + else + { + loginRetryCount = 0; // Reset after giving up + nextLoginRetryTime = 0; + } + isConnecting = false; } }; -void sendDatalinkMessage(void * arg) { +void sendDatalinkMessage(void *arg) +{ string raw; string url = baseUrlDatalink; @@ -101,24 +130,28 @@ void sendDatalinkMessage(void * arg) { url += tmessage; size_t start_pos = 0; - while ((start_pos = url.find(" ", start_pos)) != std::string::npos) { + while ((start_pos = url.find(" ", start_pos)) != std::string::npos) + { url.replace(start_pos, string(" ").length(), "%20"); start_pos += string("%20").length(); } raw.assign(httpHelper->downloadStringFromURL(url)); - if (startsWith("ok", raw.c_str())) { + if (startsWith("ok", raw.c_str())) + { if (PendingMessages.find(DatalinkToSend.callsign) != PendingMessages.end()) PendingMessages.erase(DatalinkToSend.callsign); - if (std::find(AircraftMessage.begin(), AircraftMessage.end(), DatalinkToSend.callsign.c_str()) != AircraftMessage.end()) { + if (std::find(AircraftMessage.begin(), AircraftMessage.end(), DatalinkToSend.callsign.c_str()) != AircraftMessage.end()) + { AircraftMessage.erase(std::remove(AircraftMessage.begin(), AircraftMessage.end(), DatalinkToSend.callsign.c_str()), AircraftMessage.end()); } AircraftMessageSent.push_back(DatalinkToSend.callsign.c_str()); } }; -void pollMessages(void * arg) { +void pollMessages(void *arg) +{ string raw = ""; string url = baseUrlDatalink; url += "?logon="; @@ -137,7 +170,8 @@ void pollMessages(void * arg) { string delimiter = "}} "; size_t pos = 0; std::string token; - while ((pos = raw.find(delimiter)) != std::string::npos) { + while ((pos = raw.find(delimiter)) != std::string::npos) + { token = raw.substr(1, pos); string parsed; @@ -158,27 +192,36 @@ void pollMessages(void * arg) { i++; } - if (message.type.find("telex") != std::string::npos || message.type.find("cpdlc") != std::string::npos) { - if (message.message.find("REQ") != std::string::npos || message.message.find("CLR") != std::string::npos || message.message.find("PDC") != std::string::npos || message.message.find("PREDEP") != std::string::npos || message.message.find("REQUEST") != std::string::npos) { - if (message.message.find("LOGON") != std::string::npos) { + if (message.type.find("telex") != std::string::npos || message.type.find("cpdlc") != std::string::npos) + { + if (message.message.find("REQ") != std::string::npos || message.message.find("CLR") != std::string::npos || message.message.find("PDC") != std::string::npos || message.message.find("PREDEP") != std::string::npos || message.message.find("REQUEST") != std::string::npos) + { + if (message.message.find("LOGON") != std::string::npos) + { tmessage = "UNABLE"; ttype = "CPDLC"; tdest = DatalinkToSend.callsign; _beginthread(sendDatalinkMessage, 0, NULL); - } else { - if (PlaySoundClr) { + } + else + { + if (PlaySoundClr) + { AFX_MANAGE_STATE(AfxGetStaticModuleState()); PlaySound(MAKEINTRESOURCE(IDR_WAVE1), AfxGetInstanceHandle(), SND_RESOURCE | SND_ASYNC); } AircraftDemandingClearance.push_back(message.from); } } - else if (message.message.find("WILCO") != std::string::npos || message.message.find("ROGER") != std::string::npos || message.message.find("RGR") != std::string::npos || message.message.find("ACCEPT") != std::string::npos) { - if (std::find(AircraftMessageSent.begin(), AircraftMessageSent.end(), message.from) != AircraftMessageSent.end()) { + else if (message.message.find("WILCO") != std::string::npos || message.message.find("ROGER") != std::string::npos || message.message.find("RGR") != std::string::npos || message.message.find("ACCEPT") != std::string::npos) + { + if (std::find(AircraftMessageSent.begin(), AircraftMessageSent.end(), message.from) != AircraftMessageSent.end()) + { AircraftWilco.push_back(message.from); } } - else if (message.message.length() != 0 ){ + else if (message.message.length() != 0) + { AircraftMessage.push_back(message.from); } PendingMessages[message.from] = message; @@ -186,11 +229,10 @@ void pollMessages(void * arg) { raw.erase(0, pos + delimiter.length()); } - - }; -void sendDatalinkClearance(void * arg) { +void sendDatalinkClearance(void *arg) +{ string raw; string url = baseUrlDatalink; url += "?logon="; @@ -212,9 +254,8 @@ if (DatalinkToSend.sid == "CHK" && DatalinkToSend.rwy == "09R") // CPT 09R url += "@ OFF RWY @"; url += DatalinkToSend.rwy; url += "@ VIA CPT AFTER DEP CLIMB STRAIGHT AHEAD - AT LON DME 2.0 TURN RIGHT HDG @220@ - CLIMB @6000FT"; - } - else // normal PDC message (UK Format) + else { url += "@"; url += DatalinkToSend.callsign; @@ -231,9 +272,13 @@ if (DatalinkToSend.sid == "CHK" && DatalinkToSend.rwy == "09R") // CPT 09R url += DatalinkToSend.squawk; url += "@ NEXT FREQ @"; if (DatalinkToSend.freq != "no" && DatalinkToSend.freq.size() > 5) - {url += DatalinkToSend.freq;} - else - {url += myfrequency;} + { + url += DatalinkToSend.freq; + } + else + { + url += myfrequency; + } url += "@ "; @@ -241,18 +286,22 @@ if (DatalinkToSend.sid == "CHK" && DatalinkToSend.rwy == "09R") // CPT 09R url += DatalinkToSend.message; size_t start_pos = 0; - while ((start_pos = url.find(" ", start_pos)) != std::string::npos) { + while ((start_pos = url.find(" ", start_pos)) != std::string::npos) + { url.replace(start_pos, string(" ").length(), "%20"); start_pos += string("%20").length(); } raw.assign(httpHelper->downloadStringFromURL(url)); - if (startsWith("ok", raw.c_str())) { - if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), DatalinkToSend.callsign.c_str()) != AircraftDemandingClearance.end()) { + if (startsWith("ok", raw.c_str())) + { + if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), DatalinkToSend.callsign.c_str()) != AircraftDemandingClearance.end()) + { AircraftDemandingClearance.erase(std::remove(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), DatalinkToSend.callsign.c_str()), AircraftDemandingClearance.end()); } - if (std::find(AircraftStandby.begin(), AircraftStandby.end(), DatalinkToSend.callsign.c_str()) != AircraftStandby.end()) { + if (std::find(AircraftStandby.begin(), AircraftStandby.end(), DatalinkToSend.callsign.c_str()) != AircraftStandby.end()) + { AircraftStandby.erase(std::remove(AircraftStandby.begin(), AircraftStandby.end(), DatalinkToSend.callsign.c_str()), AircraftStandby.end()); } if (PendingMessages.find(DatalinkToSend.callsign) != PendingMessages.end()) @@ -261,7 +310,7 @@ if (DatalinkToSend.sid == "CHK" && DatalinkToSend.rwy == "09R") // CPT 09R } }; -CSMRPlugin::CSMRPlugin(void) :CPlugIn(EuroScopePlugIn::COMPATIBILITY_CODE, MY_PLUGIN_NAME, MY_PLUGIN_VERSION, MY_PLUGIN_DEVELOPER, MY_PLUGIN_COPYRIGHT) +CSMRPlugin::CSMRPlugin(void) : CPlugIn(EuroScopePlugIn::COMPATIBILITY_CODE, MY_PLUGIN_NAME, MY_PLUGIN_VERSION, MY_PLUGIN_DEVELOPER, MY_PLUGIN_COPYRIGHT) { Logger::DLL_PATH = ""; @@ -282,7 +331,7 @@ CSMRPlugin::CSMRPlugin(void) :CPlugIn(EuroScopePlugIn::COMPATIBILITY_CODE, MY_PL if (httpHelper == NULL) httpHelper = new HttpHelper(); - const char * p_value; + const char *p_value; if ((p_value = GetDataFromSettings("cpdlc_logon")) != NULL) logonCallsign = p_value; @@ -290,6 +339,8 @@ CSMRPlugin::CSMRPlugin(void) :CPlugIn(EuroScopePlugIn::COMPATIBILITY_CODE, MY_PL logonCode = p_value; if ((p_value = GetDataFromSettings("cpdlc_sound")) != NULL) PlaySoundClr = bool(!!atoi(p_value)); + /* if ((p_value = GetDataFromSettings("cpdlc_autoconnect")) != NULL) + AutoConnect = bool(!!atoi(p_value)); */ char DllPathFile[_MAX_PATH]; string DllPath; @@ -309,31 +360,48 @@ CSMRPlugin::~CSMRPlugin() if (PlaySoundClr) temp = 1; SaveDataToSettings("cpdlc_sound", "Play sound on clearance request", std::to_string(temp).c_str()); + // SaveDataToSettings("cpdlc_autoconnect", "Automatically connect to Hoppie server on startup", std::to_string(AutoConnect).c_str()); try { io_service.stop(); - //vStripsThread.join(); + // vStripsThread.join(); } - catch (std::exception& e) + catch (std::exception &e) { std::cerr << e.what() << std::endl; } } -bool CSMRPlugin::OnCompileCommand(const char * sCommandLine) { +bool CSMRPlugin::OnCompileCommand(const char *sCommandLine) +{ if (startsWith(".smr connect", sCommandLine)) { - if (ControllerMyself().IsController()) { - if (!HoppieConnected) { - _beginthread(datalinkLogin, 0, NULL); + if (ControllerMyself().IsController()) + { + if (!HoppieConnected) + { + if (isConnecting) + { + DisplayUserMessage("CPDLC", "Server", "Already trying to connect!", true, true, false, true, false); + } + else if (nextLoginRetryTime > 0 && time(NULL) < nextLoginRetryTime) + { + DisplayUserMessage("CPDLC", "Server", "Waiting for next retry time!", true, true, false, true, false); + } + else + { + _beginthread(datalinkLogin, 0, NULL); + } } - else { + else + { HoppieConnected = false; DisplayUserMessage("CPDLC", "Server", "Logged off!", true, true, false, true, false); } } - else { + else + { DisplayUserMessage("CPDLC", "Error", "You are not logged in as a controller!", true, true, false, true, false); } @@ -341,12 +409,14 @@ bool CSMRPlugin::OnCompileCommand(const char * sCommandLine) { } else if (startsWith(".smr poll", sCommandLine)) { - if (HoppieConnected) { + if (HoppieConnected) + { _beginthread(pollMessages, 0, NULL); } return true; } - else if (strcmp(sCommandLine, ".smr log") == 0) { + else if (strcmp(sCommandLine, ".smr log") == 0) + { Logger::ENABLED = !Logger::ENABLED; return true; } @@ -356,6 +426,7 @@ bool CSMRPlugin::OnCompileCommand(const char * sCommandLine) { dia.m_Logon = logonCallsign.c_str(); dia.m_Password = logonCode.c_str(); dia.m_Sound = int(PlaySoundClr); + // dia.m_AutoLogon = int(AutoConnect); if (dia.DoModal() != IDOK) return true; @@ -363,23 +434,29 @@ bool CSMRPlugin::OnCompileCommand(const char * sCommandLine) { logonCallsign = dia.m_Logon; logonCode = dia.m_Password; PlaySoundClr = bool(!!dia.m_Sound); + AutoConnect = bool(!!dia.m_AutoLogon); SaveDataToSettings("cpdlc_logon", "The CPDLC logon callsign", logonCallsign.c_str()); SaveDataToSettings("cpdlc_password", "The CPDLC logon password", logonCode.c_str()); int temp = 0; if (PlaySoundClr) temp = 1; SaveDataToSettings("cpdlc_sound", "Play sound on clearance request", std::to_string(temp).c_str()); + // SaveDataToSettings("cpdlc_autoconnect", "Automatically connect to Hoppie server on startup", std::to_string(AutoConnect).c_str()); return true; } return false; } -void CSMRPlugin::OnGetTagItem(CFlightPlan FlightPlan, CRadarTarget RadarTarget, int ItemCode, int TagData, char sItemString[16], int * pColorCode, COLORREF * pRGB, double * pFontSize) { +void CSMRPlugin::OnGetTagItem(CFlightPlan FlightPlan, CRadarTarget RadarTarget, int ItemCode, int TagData, char sItemString[16], int *pColorCode, COLORREF *pRGB, double *pFontSize) +{ Logger::info(string(__FUNCSIG__)); - if (ItemCode == TAG_ITEM_DATALINK_STS) { - if (FlightPlan.IsValid()) { - if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()) != AircraftDemandingClearance.end()) { + if (ItemCode == TAG_ITEM_DATALINK_STS) + { + if (FlightPlan.IsValid()) + { + if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()) != AircraftDemandingClearance.end()) + { *pColorCode = TAG_COLOR_RGB_DEFINED; if (BLINK) *pRGB = RGB(130, 130, 130); @@ -391,7 +468,8 @@ void CSMRPlugin::OnGetTagItem(CFlightPlan FlightPlan, CRadarTarget RadarTarget, else strcpy_s(sItemString, 16, "R"); } - else if (std::find(AircraftMessage.begin(), AircraftMessage.end(), FlightPlan.GetCallsign()) != AircraftMessage.end()) { + else if (std::find(AircraftMessage.begin(), AircraftMessage.end(), FlightPlan.GetCallsign()) != AircraftMessage.end()) + { *pColorCode = TAG_COLOR_RGB_DEFINED; if (BLINK) *pRGB = RGB(130, 130, 130); @@ -399,17 +477,20 @@ void CSMRPlugin::OnGetTagItem(CFlightPlan FlightPlan, CRadarTarget RadarTarget, *pRGB = RGB(255, 255, 0); strcpy_s(sItemString, 16, "T"); } - else if (std::find(AircraftWilco.begin(), AircraftWilco.end(), FlightPlan.GetCallsign()) != AircraftWilco.end()) { + else if (std::find(AircraftWilco.begin(), AircraftWilco.end(), FlightPlan.GetCallsign()) != AircraftWilco.end()) + { *pColorCode = TAG_COLOR_RGB_DEFINED; *pRGB = RGB(0, 176, 0); strcpy_s(sItemString, 16, "V"); } - else if (std::find(AircraftMessageSent.begin(), AircraftMessageSent.end(), FlightPlan.GetCallsign()) != AircraftMessageSent.end()) { + else if (std::find(AircraftMessageSent.begin(), AircraftMessageSent.end(), FlightPlan.GetCallsign()) != AircraftMessageSent.end()) + { *pColorCode = TAG_COLOR_RGB_DEFINED; *pRGB = RGB(255, 255, 0); strcpy_s(sItemString, 16, "V"); } - else { + else + { *pColorCode = TAG_COLOR_RGB_DEFINED; *pRGB = RGB(130, 130, 130); @@ -419,16 +500,19 @@ void CSMRPlugin::OnGetTagItem(CFlightPlan FlightPlan, CRadarTarget RadarTarget, } } -void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT Pt, RECT Area) +void CSMRPlugin::OnFunctionCall(int FunctionId, const char *sItemString, POINT Pt, RECT Area) { Logger::info(string(__FUNCSIG__)); - if (FunctionId == TAG_FUNC_DATALINK_MENU) { + if (FunctionId == TAG_FUNC_DATALINK_MENU) + { CFlightPlan FlightPlan = FlightPlanSelectASEL(); bool menu_is_datalink = true; - if (FlightPlan.IsValid()) { - if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()) != AircraftDemandingClearance.end()) { + if (FlightPlan.IsValid()) + { + if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()) != AircraftDemandingClearance.end()) + { menu_is_datalink = false; } } @@ -442,35 +526,45 @@ void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT AddPopupListElement("Close", "", EuroScopePlugIn::TAG_ITEM_FUNCTION_NO, false, 2, false, true); } - if (FunctionId == TAG_FUNC_DATALINK_RESET) { + if (FunctionId == TAG_FUNC_DATALINK_RESET) + { CFlightPlan FlightPlan = FlightPlanSelectASEL(); - if (FlightPlan.IsValid()) { - if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()) != AircraftDemandingClearance.end()) { + if (FlightPlan.IsValid()) + { + if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()) != AircraftDemandingClearance.end()) + { AircraftDemandingClearance.erase(std::remove(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()), AircraftDemandingClearance.end()); } - if (std::find(AircraftStandby.begin(), AircraftStandby.end(), FlightPlan.GetCallsign()) != AircraftStandby.end()) { + if (std::find(AircraftStandby.begin(), AircraftStandby.end(), FlightPlan.GetCallsign()) != AircraftStandby.end()) + { AircraftStandby.erase(std::remove(AircraftStandby.begin(), AircraftStandby.end(), FlightPlan.GetCallsign()), AircraftStandby.end()); } - if (std::find(AircraftMessageSent.begin(), AircraftMessageSent.end(), FlightPlan.GetCallsign()) != AircraftMessageSent.end()) { + if (std::find(AircraftMessageSent.begin(), AircraftMessageSent.end(), FlightPlan.GetCallsign()) != AircraftMessageSent.end()) + { AircraftMessageSent.erase(std::remove(AircraftMessageSent.begin(), AircraftMessageSent.end(), FlightPlan.GetCallsign()), AircraftMessageSent.end()); } - if (std::find(AircraftWilco.begin(), AircraftWilco.end(), FlightPlan.GetCallsign()) != AircraftWilco.end()) { + if (std::find(AircraftWilco.begin(), AircraftWilco.end(), FlightPlan.GetCallsign()) != AircraftWilco.end()) + { AircraftWilco.erase(std::remove(AircraftWilco.begin(), AircraftWilco.end(), FlightPlan.GetCallsign()), AircraftWilco.end()); } - if (std::find(AircraftMessage.begin(), AircraftMessage.end(), FlightPlan.GetCallsign()) != AircraftMessage.end()) { + if (std::find(AircraftMessage.begin(), AircraftMessage.end(), FlightPlan.GetCallsign()) != AircraftMessage.end()) + { AircraftMessage.erase(std::remove(AircraftMessage.begin(), AircraftMessage.end(), FlightPlan.GetCallsign()), AircraftMessage.end()); } - if (PendingMessages.find(FlightPlan.GetCallsign()) != PendingMessages.end()) { + if (PendingMessages.find(FlightPlan.GetCallsign()) != PendingMessages.end()) + { PendingMessages.erase(FlightPlan.GetCallsign()); } } } - if (FunctionId == TAG_FUNC_DATALINK_STBY) { + if (FunctionId == TAG_FUNC_DATALINK_STBY) + { CFlightPlan FlightPlan = FlightPlanSelectASEL(); - if (FlightPlan.IsValid()) { + if (FlightPlan.IsValid()) + { AircraftStandby.push_back(FlightPlan.GetCallsign()); tmessage = "STANDBY"; ttype = "CPDLC"; @@ -479,10 +573,12 @@ void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT } } - if (FunctionId == TAG_FUNC_DATALINK_MESSAGE) { + if (FunctionId == TAG_FUNC_DATALINK_MESSAGE) + { CFlightPlan FlightPlan = FlightPlanSelectASEL(); - if (FlightPlan.IsValid()) { + if (FlightPlan.IsValid()) + { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CDataLinkDialog dia; @@ -506,31 +602,36 @@ void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT } } - if (FunctionId == TAG_FUNC_DATALINK_VOICE) { + if (FunctionId == TAG_FUNC_DATALINK_VOICE) + { CFlightPlan FlightPlan = FlightPlanSelectASEL(); - if (FlightPlan.IsValid()) { + if (FlightPlan.IsValid()) + { tmessage = "UNABLE CALL ON FREQ"; ttype = "CPDLC"; tdest = FlightPlan.GetCallsign(); - if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), DatalinkToSend.callsign.c_str()) != AircraftDemandingClearance.end()) { + if (std::find(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), DatalinkToSend.callsign.c_str()) != AircraftDemandingClearance.end()) + { AircraftDemandingClearance.erase(std::remove(AircraftDemandingClearance.begin(), AircraftDemandingClearance.end(), FlightPlan.GetCallsign()), AircraftDemandingClearance.end()); } - if (std::find(AircraftStandby.begin(), AircraftStandby.end(), DatalinkToSend.callsign.c_str()) != AircraftStandby.end()) { + if (std::find(AircraftStandby.begin(), AircraftStandby.end(), DatalinkToSend.callsign.c_str()) != AircraftStandby.end()) + { AircraftStandby.erase(std::remove(AircraftStandby.begin(), AircraftStandby.end(), FlightPlan.GetCallsign()), AircraftDemandingClearance.end()); } PendingMessages.erase(DatalinkToSend.callsign); _beginthread(sendDatalinkMessage, 0, NULL); } - } - if (FunctionId == TAG_FUNC_DATALINK_CONFIRM) { + if (FunctionId == TAG_FUNC_DATALINK_CONFIRM) + { CFlightPlan FlightPlan = FlightPlanSelectASEL(); - if (FlightPlan.IsValid()) { + if (FlightPlan.IsValid()) + { AFX_MANAGE_STATE(AfxGetStaticModuleState()); @@ -555,8 +656,10 @@ void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT int ClearedAltitude = FlightPlan.GetControllerAssignedData().GetClearedAltitude(); int Ta = GetTransitionAltitude(); - if (ClearedAltitude != 0) { - if (ClearedAltitude > Ta && ClearedAltitude > 2) { + if (ClearedAltitude != 0) + { + if (ClearedAltitude > Ta && ClearedAltitude > 2) + { string str = std::to_string(ClearedAltitude); for (size_t i = 0; i < 5 - str.length(); i++) str = "0" + str; @@ -565,8 +668,8 @@ void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT toReturn = "FL"; toReturn += str; } - else if (ClearedAltitude <= Ta && ClearedAltitude > 2) { - + else if (ClearedAltitude <= Ta && ClearedAltitude > 2) + { toReturn = std::to_string(ClearedAltitude); toReturn += "ft"; @@ -591,9 +694,7 @@ void CSMRPlugin::OnFunctionCall(int FunctionId, const char * sItemString, POINT myfrequency = std::to_string(ControllerMyself().GetPrimaryFrequency()).substr(0, 7); _beginthread(sendDatalinkClearance, 0, NULL); - } - } } @@ -614,22 +715,71 @@ void CSMRPlugin::OnTimer(int Counter) Logger::info(string(__FUNCSIG__)); BLINK = !BLINK; - if (HoppieConnected && ConnectionMessage) { + if (HoppieConnected && ConnectionMessage) + { DisplayUserMessage("CPDLC", "Server", "Logged in!", true, true, false, true, false); ConnectionMessage = false; } - if (FailedToConnectMessage) { + if (FailedToConnectMessage) + { DisplayUserMessage("CPDLC", "Server", "Could not login! Callsign probably in use.", true, true, false, true, false); FailedToConnectMessage = false; } - if (HoppieConnected && GetConnectionType() == CONNECTION_TYPE_NO) { + if (HoppieConnected && GetConnectionType() == CONNECTION_TYPE_NO) + { DisplayUserMessage("CPDLC", "Server", "Automatically logged off!", true, true, false, true, false); HoppieConnected = false; } - if (((clock() - timer) / CLOCKS_PER_SEC) > 10 && HoppieConnected) { + // Check if logonCode is empty or only whitespace + if (ControllerMyself().IsController() && logonCode.empty() || std::all_of(logonCode.begin(), logonCode.end(), isspace)) + { + DisplayUserMessage("CPDLC", "Error", "Logon code is empty. Please set your CPDLC password in the settings.", true, true, false, true, false); + isConnecting = false; + return; + } + + // Retry login + if (ControllerMyself().IsController() && !HoppieConnected && nextLoginRetryTime > 0 && time(NULL) >= nextLoginRetryTime) + { + isConnecting = true; + _beginthread(datalinkLogin, 0, NULL); + nextLoginRetryTime = 0; // Prevent multiple triggers + } + else if (maxLoginRetries > 0 && loginRetryCount >= maxLoginRetries && nextLoginRetryTime == 0) + { + DisplayUserMessage("CPDLC", "Error", "Maximum login retries reached. Please check your settings.", true, true, false, true, false); + HoppieConnected = false; + loginRetryCount = 0; // Reset after giving up + nextLoginRetryTime = 0; // Reset next retry time + isConnecting = false; + return; + } + else + { + DisplayUserMessage("CPDLC", "Error", "You are not logged in as a controller!", true, true, false, true, false); + } + + // Auto connection + /* if (ControllerMyself().IsController() && AutoConnect && !HoppieConnected && !isConnecting) + { + if (loginRetryCount > 0 && nextLoginRetryTime > 0 && time(NULL) < nextLoginRetryTime) + { + return; // Wait for the next retry time + } + else { + isConnecting = true; + _beginthread(datalinkLogin, 0, NULL); + } + } + else { + DisplayUserMessage("CPDLC", "Error", "You are not logged in as a controller!", true, true, false, true, false); + } */ + + if (((clock() - timer) / CLOCKS_PER_SEC) > 10 && HoppieConnected) + { _beginthread(pollMessages, 0, NULL); timer = clock(); } @@ -638,19 +788,22 @@ void CSMRPlugin::OnTimer(int Counter) { CRadarTarget RadarTarget = RadarTargetSelect(ac.c_str()); - if (RadarTarget.IsValid()) { - if (RadarTarget.GetGS() > 160) { + if (RadarTarget.IsValid()) + { + if (RadarTarget.GetGS() > 160) + { AircraftWilco.erase(std::remove(AircraftWilco.begin(), AircraftWilco.end(), ac), AircraftWilco.end()); } } } }; -CRadarScreen * CSMRPlugin::OnRadarScreenCreated(const char * sDisplayName, bool NeedRadarContent, bool GeoReferenced, bool CanBeSaved, bool CanBeCreated) +CRadarScreen *CSMRPlugin::OnRadarScreenCreated(const char *sDisplayName, bool NeedRadarContent, bool GeoReferenced, bool CanBeSaved, bool CanBeCreated) { Logger::info(string(__FUNCSIG__)); - if (!strcmp(sDisplayName, MY_PLUGIN_VIEW_AVISO)) { - CSMRRadar* rd = new CSMRRadar(); + if (!strcmp(sDisplayName, MY_PLUGIN_VIEW_AVISO)) + { + CSMRRadar *rd = new CSMRRadar(); RadarScreensOpened.push_back(rd); return rd; } @@ -660,7 +813,7 @@ CRadarScreen * CSMRPlugin::OnRadarScreenCreated(const char * sDisplayName, bool //---EuroScopePlugInExit----------------------------------------------- -void __declspec (dllexport) EuroScopePlugInExit(void) +void __declspec(dllexport) EuroScopePlugInExit(void) { for each (auto var in RadarScreensOpened) { diff --git a/vSMR/resource.h b/vSMR/resource.h index 48b49b13c..143b78aac 100644 Binary files a/vSMR/resource.h and b/vSMR/resource.h differ diff --git a/vSMR/vSMR.rc b/vSMR/vSMR.rc index 4fddda0d4..eab523582 100644 --- a/vSMR/vSMR.rc +++ b/vSMR/vSMR.rc @@ -176,18 +176,19 @@ BEGIN EDITTEXT IDC_CLB,141,52,29,14,ES_CENTER | ES_UPPERCASE | ES_AUTOHSCROLL | WS_DISABLED END -IDD_DIALOG2 DIALOGEX 0, 0, 142, 105 +IDD_DIALOG2 DIALOGEX 0, 0, 142, 125 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "CPDLC Settings" FONT 10, "Microsoft Sans Serif", 400, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,85,84,50,14 - PUSHBUTTON "Cancel",IDCANCEL,7,84,50,14 + DEFPUSHBUTTON "OK",IDOK,85,104,50,14 + PUSHBUTTON "Cancel",IDCANCEL,7,104,50,14 EDITTEXT IDC_LOGON,61,15,74,14,ES_AUTOHSCROLL LTEXT "Logon Callsign",IDC_STATIC,7,18,46,8 EDITTEXT IDC_PASSWORD,61,43,74,14,ES_PASSWORD | ES_AUTOHSCROLL LTEXT "Logon Password",IDC_STATIC,7,46,52,8 CONTROL "Play sound on clearance request",IDC_SOUND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,65,128,10 + CONTROL "Automatically connect to Hoppie server on startup", IDC_AUTOLOGON, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 7, 80, 128, 20 END