From d3ba6c008aaf4e756895c594b6bd57ab6d5a8cd0 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 14:34:37 +0200 Subject: [PATCH 01/27] Switched to .net 4.8.0 --- 02_Windows_App/Perun.sln | 4 +-- 02_Windows_App/Perun_v1/Perun_v1.csproj | 3 ++- .../Perun_v1/Properties/Resources.Designer.cs | 26 +++++++++---------- .../Perun_v1/Properties/Settings.Designer.cs | 10 +++---- 02_Windows_App/Perun_v1/app.config | 24 ++++++++--------- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/02_Windows_App/Perun.sln b/02_Windows_App/Perun.sln index a5af109..b79023a 100644 --- a/02_Windows_App/Perun.sln +++ b/02_Windows_App/Perun.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.421 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29306.81 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perun_v1", "Perun_v1\Perun_v1.csproj", "{5A710507-92E9-4664-9B91-918B8B82F107}" EndProject diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index c42be6f..df06037 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -8,7 +8,7 @@ WinExe Perun_v1 Perun - v4.6.1 + v4.8 512 true true @@ -38,6 +38,7 @@ true true true + AnyCPU diff --git a/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs b/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs index 9aee274..f337db3 100644 --- a/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs +++ b/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Ten kod został wygenerowany przez narzędzie. -// Wersja wykonawcza:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Zmiany w tym pliku mogą spowodować nieprawidłowe zachowanie i zostaną utracone, jeśli -// kod zostanie ponownie wygenerowany. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -13,13 +13,13 @@ namespace Perun_v1.Properties { /// - /// Klasa zasobu wymagająca zdefiniowania typu do wyszukiwania zlokalizowanych ciągów itd. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Ta klasa została automatycznie wygenerowana za pomocą klasy StronglyTypedResourceBuilder - // przez narzędzie, takie jak ResGen lub Visual Studio. - // Aby dodać lub usunąć składową, edytuj plik ResX, a następnie ponownie uruchom narzędzie ResGen - // z opcją /str lub ponownie utwórz projekt VS. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -33,7 +33,7 @@ namespace Perun_v1.Properties { } /// - /// Zwraca buforowane wystąpienie ResourceManager używane przez tę klasę. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ namespace Perun_v1.Properties { } /// - /// Przesłania właściwość CurrentUICulture bieżącego wątku dla wszystkich - /// przypadków przeszukiwania zasobów za pomocą tej klasy zasobów wymagającej zdefiniowania typu. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { diff --git a/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs b/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs index 0e363a5..b3dbe85 100644 --- a/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs +++ b/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Ten kod został wygenerowany przez narzędzie. -// Wersja wykonawcza:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Zmiany w tym pliku mogą spowodować nieprawidłowe zachowanie i zostaną utracone, jeśli -// kod zostanie ponownie wygenerowany. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -12,7 +12,7 @@ namespace Perun_v1.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/02_Windows_App/Perun_v1/app.config b/02_Windows_App/Perun_v1/app.config index 72175de..24fd876 100644 --- a/02_Windows_App/Perun_v1/app.config +++ b/02_Windows_App/Perun_v1/app.config @@ -1,29 +1,29 @@ - + - -
+ +
- + - + - + - + - + - + False @@ -35,10 +35,10 @@ 3306 - + - + False @@ -48,4 +48,4 @@ - \ No newline at end of file + From 150a9ab502a83ca8bbeed6c3084d2345dbfa6b18 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 14:55:09 +0200 Subject: [PATCH 02/27] Added actual nuget references --- 02_Windows_App/Perun_v1/Perun_v1.csproj | 17 ++++++++++++----- 02_Windows_App/Perun_v1/packages.config | 8 ++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 02_Windows_App/Perun_v1/packages.config diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index df06037..88f83fe 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -88,14 +88,20 @@ Properties\app.manifest - - ..\packages\Google.Protobuf.3.5.1\lib\net45\Google.Protobuf.dll + + ..\packages\BouncyCastle.1.8.3.1\lib\BouncyCastle.Crypto.dll - - ..\packages\MySql.Data.8.0.15\lib\net452\MySql.Data.dll + + ..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll + + + ..\packages\MySql.Data.8.0.17\lib\net452\MySql.Data.dll - ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\SSH.NET.2016.1.0\lib\net40\Renci.SshNet.dll @@ -146,6 +152,7 @@ + SettingsSingleFileGenerator diff --git a/02_Windows_App/Perun_v1/packages.config b/02_Windows_App/Perun_v1/packages.config new file mode 100644 index 0000000..fa00d4d --- /dev/null +++ b/02_Windows_App/Perun_v1/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From 4900ef4888799c58954d48a6fd47947f199aa7c6 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 15:22:16 +0200 Subject: [PATCH 03/27] WIP --- .../Perun_v1/01_Classes/TCPController.cs | 93 +++++++++++++++++++ 02_Windows_App/Perun_v1/Perun_v1.csproj | 1 + 2 files changed, 94 insertions(+) create mode 100644 02_Windows_App/Perun_v1/01_Classes/TCPController.cs diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs new file mode 100644 index 0000000..928fc21 --- /dev/null +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -0,0 +1,93 @@ +// This class handles TCP communication +using Newtonsoft.Json; +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +internal class TCPController +{ + // Main class for TCP listener + public static int intListenPort; // Port to connect to + public static bool boolDone; // Helper to exit main loop without killing thread + public static TcpListener tcpServer; // Listener object + public static string[] arrLogHistory; // Log history for GUI + public static string[] arrSendBuffer; // Mysql send buffer + public static Thread thrTCPListener; // Seperate thread for UDP + + public static void Create(int intListenPort, ref string[] arrLogHistory, ref string[] arrSendBuffer) + { + // Create class + TCPController.intListenPort = intListenPort; + TCPController.arrLogHistory = arrLogHistory; + TCPController.arrSendBuffer = arrSendBuffer; + } + + public static void StopListen() + { + // FInish listening + TCPController.boolDone = true; + TCPController.tcpServer.Close(); + TCPController.tcpServer = null; + + for (int i = 0; i < arrSendBuffer.Length - 1; i++) + { + arrSendBuffer[i] = null; + } + + } + + public static void StartListen() + { + Console.WriteLine("UDP Listen start"); + try + { + // Start listening to UDP + + tcpServer = new TcpListener(IPAddress.Any, intListenPort); + + string strReceivedData; + byte[] arrReceiveByteArray; + + // Start the main loop + TCPController.boolDone = false; + tcpServer.Start(); + while (!TCPController.boolDone) + { + // Start listening + Console.WriteLine("TCP: Waiting for packet"); + arrReceiveByteArray = udpListener.Receive(ref ipendpointGroupEP); + strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); + Console.WriteLine("Sender: {0} Payload: {1}", ipendpointGroupEP.ToString(), strReceivedData); + + // Add to log history and rotate + dynamic dynamicRawUDPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame + string strRawUDPFrameType = dynamicRawUDPFrame.type; + PerunHelper.LogHistoryAdd(ref arrLogHistory, "UDP packet received, type: " + strRawUDPFrameType); + + // Add to mySQL send buffer (find first empty slot) + for (int i = 0; i < arrSendBuffer.Length - 1; i++) + { + if (arrSendBuffer[i] == null) + { + arrSendBuffer[i] = strReceivedData; + break; + } + } + } + udpListener.Close(); // Close port + } + catch (Exception e) + { + // General exception found + if (e.HResult != -2147467259) + { + Console.WriteLine(e.ToString()); + PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR UDP - port may be in use"); + } + } + Console.WriteLine("UDP listen stop"); + } +} diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index 88f83fe..4422c04 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -123,6 +123,7 @@ + From 52ecfda6c56eb2ee34522ddd17209ea5368f6ee2 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 16:00:53 +0200 Subject: [PATCH 04/27] WIP - main form change --- 02_Windows_App/Perun_v1/01_Classes/Program.cs | 31 +--- .../Perun_v1/01_Classes/TCPController.cs | 41 +++-- .../Perun_v1/02_Forms/form_Main.Designer.cs | 96 ++++++----- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 149 ++---------------- .../Perun_v1/Properties/Settings.Designer.cs | 40 +---- .../Perun_v1/Properties/Settings.settings | 14 +- 02_Windows_App/Perun_v1/app.config | 26 ++- 7 files changed, 112 insertions(+), 285 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/Program.cs b/02_Windows_App/Perun_v1/01_Classes/Program.cs index 001bb6d..7d0dff1 100644 --- a/02_Windows_App/Perun_v1/01_Classes/Program.cs +++ b/02_Windows_App/Perun_v1/01_Classes/Program.cs @@ -11,37 +11,22 @@ namespace Perun_v1 /// // Mutex to block multiple instances - static Mutex mutex = new Mutex(true, "{5a710507-92e9-4664-9b91-918b8b82f107}"); + //static Mutex mutex = new Mutex(true, "{5a710507-92e9-4664-9b91-918b8b82f107}"); [STAThread] static void Main() { - // Check if no other instances running - if (mutex.WaitOne(TimeSpan.Zero, true)) - { - // Only instance - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.ApplicationExit += new EventHandler(Application_ApplicationExit); + // Only instance + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.ApplicationExit += new EventHandler(Application_ApplicationExit); - void Application_ApplicationExit(object sender, EventArgs e) - { - Properties.Settings.Default.Save(); // We will save settings on exit - } - Application.Run(new form_Main()); // Run main form - mutex.ReleaseMutex(); // Release mutex - } - else + void Application_ApplicationExit(object sender, EventArgs e) { - // Multiple instance - send our Win32 message to make the currently running instance jump to front - NativeMethods.PostMessage( - (IntPtr)NativeMethods.HWND_BROADCAST, - NativeMethods.WM_SHOWME, - IntPtr.Zero, - IntPtr.Zero); - MessageBox.Show("Only one Perun instance is allowed.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Information); + Properties.Settings.Default.Save(); // We will save settings on exit } + Application.Run(new form_Main()); // Run main form } } } diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index 928fc21..92ecbf9 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -29,7 +29,7 @@ internal class TCPController { // FInish listening TCPController.boolDone = true; - TCPController.tcpServer.Close(); + TCPController.tcpServer.Stop(); TCPController.tcpServer = null; for (int i = 0; i < arrSendBuffer.Length - 1; i++) @@ -57,27 +57,36 @@ internal class TCPController while (!TCPController.boolDone) { // Start listening + Console.WriteLine("TCP: Waiting for packet"); - arrReceiveByteArray = udpListener.Receive(ref ipendpointGroupEP); - strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); - Console.WriteLine("Sender: {0} Payload: {1}", ipendpointGroupEP.ToString(), strReceivedData); + TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it + NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages - // Add to log history and rotate - dynamic dynamicRawUDPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame - string strRawUDPFrameType = dynamicRawUDPFrame.type; - PerunHelper.LogHistoryAdd(ref arrLogHistory, "UDP packet received, type: " + strRawUDPFrameType); - - // Add to mySQL send buffer (find first empty slot) - for (int i = 0; i < arrSendBuffer.Length - 1; i++) + while (tcpClient.Connected && !TCPController.boolDone) //while the client is connected, we look for incoming messages { - if (arrSendBuffer[i] == null) + arrReceiveByteArray = new byte[1024]; //the messages arrive as byte array + ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client + strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); + Console.WriteLine("Sender: {0} Payload: {1}", null , strReceivedData); + + dynamic dynamicRawTCPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame + string strRawTCPFrameType = dynamicRawTCPFrame.type; + + PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP packet received, type: " + strRawTCPFrameType); + + // Add to mySQL send buffer (find first empty slot) + for (int i = 0; i < arrSendBuffer.Length - 1; i++) { - arrSendBuffer[i] = strReceivedData; - break; + if (arrSendBuffer[i] == null) + { + arrSendBuffer[i] = strReceivedData; + break; + } } } + } - udpListener.Close(); // Close port + tcpServer.Stop(); } catch (Exception e) { @@ -88,6 +97,6 @@ internal class TCPController PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR UDP - port may be in use"); } } - Console.WriteLine("UDP listen stop"); + Console.WriteLine("TCP listen stop"); } } diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs index 723b816..2994e97 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs @@ -61,10 +61,10 @@ this.tim_200ms = new System.Windows.Forms.Timer(this.components); this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.con_txt_3rd_lotatc2 = new System.Windows.Forms.MaskedTextBox(); - this.con_txt_3rd_srs2 = new System.Windows.Forms.MaskedTextBox(); - this.con_check_3rd_lotatc2 = new System.Windows.Forms.CheckBox(); - this.con_check_3rd_srs2 = new System.Windows.Forms.CheckBox(); + this.label8 = new System.Windows.Forms.Label(); + this.con_txt_dcs_instance = new System.Windows.Forms.MaskedTextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.con_txt_dcs_server_port = new System.Windows.Forms.MaskedTextBox(); this.con_GroupBox_1.SuspendLayout(); this.con_GroupBox_2.SuspendLayout(); this.con_GroupBox_3.SuspendLayout(); @@ -84,7 +84,7 @@ // // con_Button_Listen_ON // - this.con_Button_Listen_ON.Location = new System.Drawing.Point(12, 517); + this.con_Button_Listen_ON.Location = new System.Drawing.Point(12, 519); this.con_Button_Listen_ON.Name = "con_Button_Listen_ON"; this.con_Button_Listen_ON.Size = new System.Drawing.Size(86, 39); this.con_Button_Listen_ON.TabIndex = 2; @@ -95,7 +95,7 @@ // con_Button_Listen_OFF // this.con_Button_Listen_OFF.Enabled = false; - this.con_Button_Listen_OFF.Location = new System.Drawing.Point(104, 517); + this.con_Button_Listen_OFF.Location = new System.Drawing.Point(104, 519); this.con_Button_Listen_OFF.Name = "con_Button_Listen_OFF"; this.con_Button_Listen_OFF.Size = new System.Drawing.Size(86, 39); this.con_Button_Listen_OFF.TabIndex = 3; @@ -111,7 +111,7 @@ this.con_GroupBox_1.Size = new System.Drawing.Size(324, 176); this.con_GroupBox_1.TabIndex = 4; this.con_GroupBox_1.TabStop = false; - this.con_GroupBox_1.Text = "UDP log"; + this.con_GroupBox_1.Text = "Data log"; // // tim_1000ms // @@ -225,12 +225,12 @@ this.con_GroupBox_3.Controls.Add(this.con_txt_3rd_srs); this.con_GroupBox_3.Controls.Add(this.con_check_3rd_lotatc); this.con_GroupBox_3.Controls.Add(this.con_check_3rd_srs); - this.con_GroupBox_3.Location = new System.Drawing.Point(12, 187); + this.con_GroupBox_3.Location = new System.Drawing.Point(12, 261); this.con_GroupBox_3.Name = "con_GroupBox_3"; this.con_GroupBox_3.Size = new System.Drawing.Size(324, 68); this.con_GroupBox_3.TabIndex = 6; this.con_GroupBox_3.TabStop = false; - this.con_GroupBox_3.Text = "Instance #1"; + this.con_GroupBox_3.Text = "3rd party"; // // con_txt_3rd_lotatc // @@ -270,7 +270,7 @@ // // con_Button_Quit // - this.con_Button_Quit.Location = new System.Drawing.Point(251, 517); + this.con_Button_Quit.Location = new System.Drawing.Point(251, 519); this.con_Button_Quit.Name = "con_Button_Quit"; this.con_Button_Quit.Size = new System.Drawing.Size(86, 39); this.con_Button_Quit.TabIndex = 7; @@ -332,63 +332,59 @@ // // groupBox1 // - this.groupBox1.Controls.Add(this.con_txt_3rd_lotatc2); - this.groupBox1.Controls.Add(this.con_txt_3rd_srs2); - this.groupBox1.Controls.Add(this.con_check_3rd_lotatc2); - this.groupBox1.Controls.Add(this.con_check_3rd_srs2); - this.groupBox1.Location = new System.Drawing.Point(12, 261); + this.groupBox1.Controls.Add(this.label8); + this.groupBox1.Controls.Add(this.con_txt_dcs_instance); + this.groupBox1.Controls.Add(this.label7); + this.groupBox1.Controls.Add(this.con_txt_dcs_server_port); + this.groupBox1.Location = new System.Drawing.Point(12, 187); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(324, 68); this.groupBox1.TabIndex = 7; this.groupBox1.TabStop = false; - this.groupBox1.Text = "Instance #2"; + this.groupBox1.Text = "DCS Connection"; // - // con_txt_3rd_lotatc2 + // label8 // - this.con_txt_3rd_lotatc2.Location = new System.Drawing.Point(123, 39); - this.con_txt_3rd_lotatc2.Name = "con_txt_3rd_lotatc2"; - this.con_txt_3rd_lotatc2.Size = new System.Drawing.Size(190, 20); - this.con_txt_3rd_lotatc2.TabIndex = 4; - this.con_txt_3rd_lotatc2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.con_txt_3rd_lotatc2_Click); + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(41, 45); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(62, 13); + this.label8.TabIndex = 12; + this.label8.Text = "Instance ID"; // - // con_txt_3rd_srs2 + // con_txt_dcs_instance // - this.con_txt_3rd_srs2.Location = new System.Drawing.Point(123, 16); - this.con_txt_3rd_srs2.Name = "con_txt_3rd_srs2"; - this.con_txt_3rd_srs2.Size = new System.Drawing.Size(190, 20); - this.con_txt_3rd_srs2.TabIndex = 3; - this.con_txt_3rd_srs2.MouseClick += new System.Windows.Forms.MouseEventHandler(this.con_txt_3rd_srs2_Click); + this.con_txt_dcs_instance.Location = new System.Drawing.Point(106, 42); + this.con_txt_dcs_instance.Name = "con_txt_dcs_instance"; + this.con_txt_dcs_instance.Size = new System.Drawing.Size(207, 20); + this.con_txt_dcs_instance.TabIndex = 11; // - // con_check_3rd_lotatc2 + // label7 // - this.con_check_3rd_lotatc2.AutoSize = true; - this.con_check_3rd_lotatc2.Location = new System.Drawing.Point(6, 42); - this.con_check_3rd_lotatc2.Name = "con_check_3rd_lotatc2"; - this.con_check_3rd_lotatc2.Size = new System.Drawing.Size(100, 17); - this.con_check_3rd_lotatc2.TabIndex = 1; - this.con_check_3rd_lotatc2.Text = "LotATC json file"; - this.con_check_3rd_lotatc2.UseVisualStyleBackColor = true; + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(41, 19); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(59, 13); + this.label7.TabIndex = 10; + this.label7.Text = "Server port"; // - // con_check_3rd_srs2 + // con_txt_dcs_server_port // - this.con_check_3rd_srs2.AutoSize = true; - this.con_check_3rd_srs2.Location = new System.Drawing.Point(6, 19); - this.con_check_3rd_srs2.Name = "con_check_3rd_srs2"; - this.con_check_3rd_srs2.Size = new System.Drawing.Size(111, 17); - this.con_check_3rd_srs2.TabIndex = 0; - this.con_check_3rd_srs2.Text = "DCS SRS json file"; - this.con_check_3rd_srs2.UseVisualStyleBackColor = true; + this.con_txt_dcs_server_port.Location = new System.Drawing.Point(106, 16); + this.con_txt_dcs_server_port.Name = "con_txt_dcs_server_port"; + this.con_txt_dcs_server_port.Size = new System.Drawing.Size(207, 20); + this.con_txt_dcs_server_port.TabIndex = 3; // // form_Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(349, 558); + this.ClientSize = new System.Drawing.Size(349, 570); this.Controls.Add(this.groupBox1); + this.Controls.Add(this.con_GroupBox_3); this.Controls.Add(this.label5); this.Controls.Add(this.con_lab_github); this.Controls.Add(this.con_Button_Quit); - this.Controls.Add(this.con_GroupBox_3); this.Controls.Add(this.con_GroupBox_2); this.Controls.Add(this.con_GroupBox_1); this.Controls.Add(this.con_Button_Listen_OFF); @@ -447,10 +443,10 @@ private System.Windows.Forms.Timer tim_200ms; private System.Windows.Forms.NotifyIcon notifyIcon1; private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.MaskedTextBox con_txt_3rd_lotatc2; - private System.Windows.Forms.MaskedTextBox con_txt_3rd_srs2; - private System.Windows.Forms.CheckBox con_check_3rd_lotatc2; - private System.Windows.Forms.CheckBox con_check_3rd_srs2; + private System.Windows.Forms.MaskedTextBox con_txt_dcs_server_port; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.MaskedTextBox con_txt_dcs_instance; } } diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index cd3e7f9..2df3fca 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -41,10 +41,9 @@ namespace Perun_v1 con_txt_3rd_srs.Text = Properties.Settings.Default.OTHER_SRS_FILE; con_check_3rd_lotatc.Checked = Properties.Settings.Default.OTHER_LOTATC_USE; con_check_3rd_srs.Checked = Properties.Settings.Default.OTHER_SRS_USE; - con_txt_3rd_lotatc2.Text = Properties.Settings.Default.OTHER_LOTATC_FILE2; - con_txt_3rd_srs2.Text = Properties.Settings.Default.OTHER_SRS_FILE2; - con_check_3rd_lotatc2.Checked = Properties.Settings.Default.OTHER_LOTATC_USE2; - con_check_3rd_srs2.Checked = Properties.Settings.Default.OTHER_SRS_USE2; + con_txt_dcs_server_port.Text = Properties.Settings.Default.DCS_Server_Port.ToString(); + con_txt_dcs_instance.Text = Properties.Settings.Default.DCS_Instance.ToString(); + } private void form_Main_SaveSettings() @@ -61,10 +60,9 @@ namespace Perun_v1 Properties.Settings.Default.OTHER_SRS_FILE = con_txt_3rd_srs.Text; Properties.Settings.Default.OTHER_LOTATC_USE = con_check_3rd_lotatc.Checked; Properties.Settings.Default.OTHER_SRS_USE = con_check_3rd_srs.Checked; - Properties.Settings.Default.OTHER_LOTATC_FILE2 = con_txt_3rd_lotatc2.Text; - Properties.Settings.Default.OTHER_SRS_FILE2 = con_txt_3rd_srs2.Text; - Properties.Settings.Default.OTHER_LOTATC_USE2 = con_check_3rd_lotatc2.Checked; - Properties.Settings.Default.OTHER_SRS_USE2 = con_check_3rd_srs2.Checked; + + Properties.Settings.Default.DCS_Server_Port = Int32.Parse(con_txt_dcs_server_port.Text); + Properties.Settings.Default.DCS_Instance = Int32.Parse(con_txt_dcs_instance.Text); Properties.Settings.Default.Save(); } @@ -83,10 +81,8 @@ namespace Perun_v1 con_txt_3rd_srs.Enabled = false; con_check_3rd_lotatc.Enabled = false; con_check_3rd_srs.Enabled = false; - con_txt_3rd_lotatc2.Enabled = false; - con_txt_3rd_srs2.Enabled = false; - con_check_3rd_lotatc2.Enabled = false; - con_check_3rd_srs2.Enabled = false; + con_txt_dcs_server_port.Enabled = false; + con_txt_dcs_instance.Enabled = false; } private void form_Main_EnableControls() @@ -104,10 +100,9 @@ namespace Perun_v1 con_txt_3rd_srs.Enabled = true; con_check_3rd_lotatc.Enabled = true; con_check_3rd_srs.Enabled = true; - con_txt_3rd_lotatc2.Enabled = true; - con_txt_3rd_srs2.Enabled = true; - con_check_3rd_lotatc2.Enabled = true; - con_check_3rd_srs2.Enabled = true; + con_txt_dcs_server_port.Enabled = true; + con_txt_dcs_instance.Enabled = true; + } // ################################ User input ################################ @@ -188,36 +183,6 @@ namespace Perun_v1 } } - private void con_txt_3rd_srs2_Click(object sender, MouseEventArgs e) - { - // Chose SRS Json file - if (openFileDialog_SRS.ShowDialog() == DialogResult.OK) - { - con_txt_3rd_srs2.Text = openFileDialog_SRS.FileName; - con_check_3rd_srs2.Checked = true; - } - else - { - con_txt_3rd_srs2.Text = ""; - con_check_3rd_srs2.Checked = false; - } - } - - private void con_txt_3rd_lotatc2_Click(object sender, MouseEventArgs e) - { - // Chose LotATC Json file - if (openFileDialog_LotATC.ShowDialog() == DialogResult.OK) - { - con_txt_3rd_lotatc2.Text = openFileDialog_LotATC.FileName; - con_check_3rd_lotatc2.Checked = true; - } - else - { - con_txt_3rd_lotatc2.Text = ""; - con_check_3rd_lotatc2.Checked = false; - } - } - // ################################ Form state ################################ private void con_Button_Quit_Click(object sender, EventArgs e) { @@ -323,13 +288,9 @@ namespace Perun_v1 // Main timer to send JSON files to MySQL string strSRSJson = ""; string strLotATCJson = ""; - string strSRSJson2 = ""; - string strLotATCJson2 = ""; bool boolSRSdefault = true; bool boolLotATCdefault = true; - bool boolSRSdefault2 = true; - bool boolLotATCdefault2 = true; // Handle SRS - TBD clean code for multiinstance if (con_check_3rd_srs.Checked) @@ -396,70 +357,6 @@ namespace Perun_v1 } DatabaseController.SendToMySql(strSRSJson); - if (con_check_3rd_srs2.Checked) - { - try - { - strSRSJson2 = System.IO.File.ReadAllText(con_txt_3rd_srs2.Text); - dynamic raw_lotatc = JsonConvert.DeserializeObject(strSRSJson2); - - for (int i = 0; i < raw_lotatc.Count; i++) - { - - if (raw_lotatc[i].RadioInfo != null) - { - - int temp = raw_lotatc[i].RadioInfo.radios.Count - 1; - for (int j = temp; j >= 0; j--) - { - raw_lotatc[i].RadioInfo.radios[j].enc.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].encKey.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].encMode.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].freqMax.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].freqMin.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].modulation.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].freqMode.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].volMode.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].expansion.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].channel.Parent.Remove(); - raw_lotatc[i].RadioInfo.radios[j].simul.Parent.Remove(); - - if (raw_lotatc[i].RadioInfo.radios[j].name == "No Radio") - { - raw_lotatc[i].RadioInfo.radios[j].Remove(); - } - } - raw_lotatc[i].ClientChannelId.Parent.Remove(); - raw_lotatc[i].RadioInfo.simultaneousTransmission.Parent.Remove(); - } - } - - if (raw_lotatc.Count > 0) - { - strSRSJson2 = JsonConvert.SerializeObject(raw_lotatc); - strSRSJson2 = "{'type':'100','instance':'2','payload':'" + strSRSJson2 + "'}"; - } - else - { - strSRSJson2 = "{'type':'100','instance':'2','payload':{'ignore':'false'}}"; // No SRS clients connected - } - boolSRSdefault2 = false; - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#2 > SRS data loaded"); - - } - catch - { - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#2 > SRS data ERROR"); - } - - - } - if (boolSRSdefault2) - { - strSRSJson2 = "{'type':'100','instance':'2','payload':{'ignore':'true'}}"; - } - DatabaseController.SendToMySql(strSRSJson2); - // Handle LotATC - TBD clean code for multiinstance if (con_check_3rd_lotatc.Checked) { @@ -484,30 +381,6 @@ namespace Perun_v1 strLotATCJson = "{'type':'101','instance':'1','payload':{'ignore':'true'}}"; // No LotATC controller connected } DatabaseController.SendToMySql(strLotATCJson); - - if (con_check_3rd_lotatc2.Checked) - { - try - { - strLotATCJson2 = System.IO.File.ReadAllText(con_txt_3rd_lotatc2.Text); - dynamic raw_srs = JsonConvert.DeserializeObject(strLotATCJson2); - - strLotATCJson2 = "{'type':'101','instance':'2','payload':'" + strLotATCJson2 + "'}"; - boolLotATCdefault2 = false; - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#2 > LotATC data loaded"); - } - catch - { - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#2 > LotATC data ERROR"); - } - - - } - if (boolLotATCdefault2) - { - strLotATCJson2 = "{'type':'101','instance':'2','payload':{'ignore':'true'}}"; // No LotATC controller connected - } - DatabaseController.SendToMySql(strLotATCJson2); } } } diff --git a/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs b/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs index b3dbe85..778c811 100644 --- a/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs +++ b/02_Windows_App/Perun_v1/Properties/Settings.Designer.cs @@ -133,49 +133,25 @@ namespace Perun_v1.Properties { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string OTHER_LOTATC_FILE2 { + [global::System.Configuration.DefaultSettingValueAttribute("48620")] + public int DCS_Server_Port { get { - return ((string)(this["OTHER_LOTATC_FILE2"])); + return ((int)(this["DCS_Server_Port"])); } set { - this["OTHER_LOTATC_FILE2"] = value; + this["DCS_Server_Port"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public string OTHER_SRS_FILE2 { + [global::System.Configuration.DefaultSettingValueAttribute("1")] + public int DCS_Instance { get { - return ((string)(this["OTHER_SRS_FILE2"])); + return ((int)(this["DCS_Instance"])); } set { - this["OTHER_SRS_FILE2"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool OTHER_LOTATC_USE2 { - get { - return ((bool)(this["OTHER_LOTATC_USE2"])); - } - set { - this["OTHER_LOTATC_USE2"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool OTHER_SRS_USE2 { - get { - return ((bool)(this["OTHER_SRS_USE2"])); - } - set { - this["OTHER_SRS_USE2"] = value; + this["DCS_Instance"] = value; } } } diff --git a/02_Windows_App/Perun_v1/Properties/Settings.settings b/02_Windows_App/Perun_v1/Properties/Settings.settings index 137835e..37e5157 100644 --- a/02_Windows_App/Perun_v1/Properties/Settings.settings +++ b/02_Windows_App/Perun_v1/Properties/Settings.settings @@ -29,17 +29,11 @@ 3306 - - + + 48620 - - - - - False - - - False + + 1 \ No newline at end of file diff --git a/02_Windows_App/Perun_v1/app.config b/02_Windows_App/Perun_v1/app.config index 24fd876..02494be 100644 --- a/02_Windows_App/Perun_v1/app.config +++ b/02_Windows_App/Perun_v1/app.config @@ -8,22 +8,22 @@ - + - + - + - + - + - + False @@ -34,17 +34,11 @@ 3306 - - + + 48620 - - - - - False - - - False + + 1 From df7155f061c2efb96f82c3941d0499ae202dc384 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 17:48:41 +0200 Subject: [PATCH 05/27] Switched to TCP --- .../Perun_v1/01_Classes/TCPController.cs | 87 ++++++++++--------- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 34 +++++--- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index 92ecbf9..ef411e5 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -41,62 +41,65 @@ internal class TCPController public static void StartListen() { - Console.WriteLine("UDP Listen start"); - try + Console.WriteLine("TCP Listen start"); + while (!TCPController.boolDone) { - // Start listening to UDP - - tcpServer = new TcpListener(IPAddress.Any, intListenPort); - - string strReceivedData; - byte[] arrReceiveByteArray; - - // Start the main loop - TCPController.boolDone = false; - tcpServer.Start(); - while (!TCPController.boolDone) + try { - // Start listening - - Console.WriteLine("TCP: Waiting for packet"); - TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it - NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages + // Start listening to UDP - while (tcpClient.Connected && !TCPController.boolDone) //while the client is connected, we look for incoming messages + tcpServer = new TcpListener(IPAddress.Any, intListenPort); + + string strReceivedData; + byte[] arrReceiveByteArray; + + // Start the main loop + TCPController.boolDone = false; + tcpServer.Start(); + while (!TCPController.boolDone) { - arrReceiveByteArray = new byte[1024]; //the messages arrive as byte array - ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client - strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); - Console.WriteLine("Sender: {0} Payload: {1}", null , strReceivedData); + // Start listening - dynamic dynamicRawTCPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame - string strRawTCPFrameType = dynamicRawTCPFrame.type; + Console.WriteLine("TCP: Waiting for packet"); + TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it + NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages - PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP packet received, type: " + strRawTCPFrameType); - - // Add to mySQL send buffer (find first empty slot) - for (int i = 0; i < arrSendBuffer.Length - 1; i++) + while (tcpClient.Connected && !TCPController.boolDone) //while the client is connected, we look for incoming messages { - if (arrSendBuffer[i] == null) + arrReceiveByteArray = new byte[1024]; //the messages arrive as byte array + ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client + strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); + Console.WriteLine("Sender: {0} Payload: {1}", null, strReceivedData); + + dynamic dynamicRawTCPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame + string strRawTCPFrameType = dynamicRawTCPFrame.type; + + PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP packet received, type: " + strRawTCPFrameType); + + // Add to mySQL send buffer (find first empty slot) + for (int i = 0; i < arrSendBuffer.Length - 1; i++) { - arrSendBuffer[i] = strReceivedData; - break; + if (arrSendBuffer[i] == null) + { + arrSendBuffer[i] = strReceivedData; + break; + } } } - } + } + tcpServer.Stop(); } - tcpServer.Stop(); - } - catch (Exception e) - { - // General exception found - if (e.HResult != -2147467259) + catch (Exception e) { - Console.WriteLine(e.ToString()); - PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR UDP - port may be in use"); + // General exception found + if (e.HResult != -2147467259) + { + Console.WriteLine(e.ToString()); + PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR TCP - port may be in use"); + } } + //Console.WriteLine("TCP listen stop"); } - Console.WriteLine("TCP listen stop"); } } diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index 2df3fca..fbaee8e 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -109,10 +109,15 @@ namespace Perun_v1 private void con_Button_Listen_ON_Click(object sender, EventArgs e) { // Start listening - UDPController.Create(48620, ref Globals.arrLogHistory, ref arrSendBuffer); - UDPController.thrUDPListener = new Thread(UDPController.StartListen); - UDPController.thrUDPListener.Start(); - UDPController.thrUDPListener.Name = "UDPThread"; + //UDPController.Create(48620, ref Globals.arrLogHistory, ref arrSendBuffer); + //UDPController.thrUDPListener = new Thread(UDPController.StartListen); + //UDPController.thrUDPListener.Start(); + //UDPController.thrUDPListener.Name = "UDPThread"; + + TCPController.Create(48620, ref Globals.arrLogHistory, ref arrSendBuffer); + TCPController.thrTCPListener = new Thread(TCPController.StartListen); + TCPController.thrTCPListener.Start(); + TCPController.thrTCPListener.Name = "TCPThread"; form_Main_DisableControls(); // Disable controlls form_Main_SaveSettings(); // Save settings @@ -131,7 +136,8 @@ namespace Perun_v1 // Stop listening try { - UDPController.StopListen(); + //UDPController.StopListen(); + TCPController.StopListen(); } catch (Exception ex) { @@ -334,26 +340,26 @@ namespace Perun_v1 if (raw_lotatc.Count > 0) { strSRSJson = JsonConvert.SerializeObject(raw_lotatc); - strSRSJson = "{'type':'100','instance':'1','payload':'" + strSRSJson + "'}"; + strSRSJson = "{'type':'100','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':'" + strSRSJson + "'}"; } else { - strSRSJson = "{'type':'100','instance':'1','payload':{'ignore':'false'}}"; // No SRS clients connected + strSRSJson = "{'type':'100','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'false'}}"; // No SRS clients connected } boolSRSdefault = false; - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#1 > SRS data loaded"); + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > SRS data loaded"); } catch { - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#1 > SRS data ERROR"); + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > SRS data ERROR"); } } if (boolSRSdefault) { - strSRSJson = "{'type':'100','instance':'1','payload':{'ignore':'true'}}"; + strSRSJson = "{'type':'100','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'true'}}"; } DatabaseController.SendToMySql(strSRSJson); @@ -365,20 +371,20 @@ namespace Perun_v1 strLotATCJson = System.IO.File.ReadAllText(con_txt_3rd_lotatc.Text); dynamic raw_srs = JsonConvert.DeserializeObject(strLotATCJson); - strLotATCJson = "{'type':'101','instance':'1','payload':'" + strLotATCJson + "'}"; + strLotATCJson = "{'type':'101','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':'" + strLotATCJson + "'}"; boolLotATCdefault = false; - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#1 > LotATC data loaded"); + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > LotATC data loaded"); } catch { - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#1 > LotATC data ERROR"); + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > LotATC data ERROR"); } } if (boolLotATCdefault) { - strLotATCJson = "{'type':'101','instance':'1','payload':{'ignore':'true'}}"; // No LotATC controller connected + strLotATCJson = "{'type':'101','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'true'}}"; // No LotATC controller connected } DatabaseController.SendToMySql(strLotATCJson); } From 17a2905b144e8025ed23e4f8851132d16724cb48 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 17:57:46 +0200 Subject: [PATCH 06/27] Readme update --- 02_Windows_App/Perun_v1/01_Classes/TCPController.cs | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index ef411e5..d1e4c80 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -96,7 +96,7 @@ internal class TCPController if (e.HResult != -2147467259) { Console.WriteLine(e.ToString()); - PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR TCP - port may be in use"); + PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP error - connection closed or port in use"); } } //Console.WriteLine("TCP listen stop"); diff --git a/README.md b/README.md index 252cbb9..035485b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Core: * DCS World stable or DCS World beta * **(Optional)** For MySQL Export: * MySQL server with read/write access (tested with v5.7.21) - * .NET Framework 4.6.1 + * .NET Framework 4.8.0 3rd party applications support: * for [DCS SRS](https://github.com/ciribob/DCS-SimpleRadioStandalone/releases) integration location of the clients-list.json file will be required (by default: SRS Server folder), "Auto Export List" option has to be enabled - see [SRS documentation](https://github.com/ciribob/DCS-SimpleRadioStandalone/wiki) @@ -39,7 +39,7 @@ Core: * click connect and leave the app running in the background * Start DCS World and host multiplayer session * by default the JSON is written into Scripts\Json folder located in your Saved Games DCS folder tree - * by default the UDP port 48620 is in use as target port + * by default the TCP port 48620 is in use as target port * Data shall be filling your MySQL database ## Data packets @@ -50,10 +50,10 @@ Core: * ```ID: 3```, available slots list and coalitions * coalitions - available coalitions * slots - available slots -* ```ID: 4```, stores mission data **WIP: not yet implemented** +* ```ID: 4```, stores mission data * ```ID: 50```, chat event * ```ID: 51```, game event -* ```ID: 52```, player stats **WIP: not yet implemented** +* ```ID: 52```, player stats * ```ID: 53```, player login to DCS server * ```ID: 100```, DCS SRS's client-list.json * ```ID: 101```, LotATC's stats.json From 36c713ba3fc3f02a196056df1259c37bbb029407 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 12 Sep 2019 18:14:05 +0200 Subject: [PATCH 07/27] Updated perun.lua for 8.0.0 --- 01_DCS/Hooks/Perun.lua | 45 +++++++++++++------ .../Perun_v1/01_Classes/TCPController.cs | 3 +- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 2 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/01_DCS/Hooks/Perun.lua b/01_DCS/Hooks/Perun.lua index 7dd6fb1..07c84d0 100644 --- a/01_DCS/Hooks/Perun.lua +++ b/01_DCS/Hooks/Perun.lua @@ -9,9 +9,9 @@ package.cpath = package.cpath..";"..lfs.currentdir().."/LuaSocket/?.dll" Perun.RefreshStatus = 15 -- (int) base refresh rate in seconds to send status update (values lower than 60 may affect performance!) Perun.RefreshMission = 60 -- (int) refresh rate in seconds to send mission information (values lower than 60 may affect performance!) -Perun.UDPTargetPort = 48620 -- (int) UDP port to send data to -Perun.UDPSourcePort = 48621 -- (int) UDP port to send data from -Perun.Instance = 1 -- (int) Id number of instance (if multiple DCS instances are to run at the same PC) +Perun.TCPTargetPort = 48620 -- (int) TCP port to send data to +Perun.TCPPerunHost = "localhost" -- (string) IP adress of the Perun instance or "localhost" +Perun.Instance = 2 -- (int) Id number of instance (if multiple DCS instances are to run at the same PC) Perun.JsonStatusLocation = "Scripts\\Json\\" -- (string) folder relative do user's SaveGames DCS folder -> status file updated each RefreshMission Perun.MOTD_L1 = "Witamy na serwerze Gildia.org !" -- (string) Message send to players connecting the server - Line 1 Perun.MOTD_L2 = "Wymagamy obecnosci DCS SRS oraz TeamSpeak - szczegoly na forum" -- (string) Message send to players connecting the server - Line 2 @@ -20,7 +20,7 @@ Perun.MOTD_L2 = "Wymagamy obecnosci DCS SRS oraz TeamSpeak - szczegoly na forum" -- Variable init -Perun.Version = "v0.6.0" +Perun.Version = "v0.8.0" Perun.StatusData = {} Perun.SlotsData = {} Perun.MissionData = {} @@ -33,7 +33,7 @@ Perun.lastSentMission =0 Perun.JsonStatusLocation = lfs.writedir() .. Perun.JsonStatusLocation Perun.socket = require("socket") Perun.IsServer = true --DCS.isServer( ) -- TBD looks like DCS API error, always returning True -Perun.UDPSourcePort = Perun.UDPSourcePort + Perun.Instance - 1 +Perun.TCPSourcePort = Perun.TCPTargetPort + 10 + Perun.Instance - 1 -- ########### Helper function definitions ########### function stripChars(str) @@ -153,11 +153,34 @@ Perun.SideID2Name = function(id) end -- ########### Main code ########### + Perun.AddLog = function(text) -- Adds logs to DCS.log file net.log("Perun : ".. text) end +Perun.ConnectToPerun = function () + Perun.AddLog("Connecting to TCP server") + Perun.TCP = assert(Perun.socket.tcp()) + Perun.TCP:settimeout(2000) + _, err = Perun.TCP:connect(Perun.TCPPerunHost, Perun.TCPTargetPort) + if err then + Perun.AddLog("TCP connection error : " .. err) + else + Perun.AddLog("Connected to TCP server") + end +end + +Perun.SendPacket = function (data_id,temp) + _, err = Perun.TCP:send(temp) + if err then + Perun.AddLog("Packed drop " .. data_id .. ", error: " .. err) + Perun.ConnectToPerun() + else + Perun.AddLog("Packet send " .. data_id) + end +end + Perun.UpdateJsonStatus = function() -- Updates status json file TempData={} @@ -184,8 +207,7 @@ Perun.Send = function(data_id, data_package) temp=net.lua2json(TempData) temp=stripChars(temp) - Perun.UDP:send(temp) - Perun.AddLog("Packet send "..data_id) + Perun.SendPacket(data_id,temp) end Perun.UpdateStatusPart = function(part_id, data_package) @@ -259,6 +281,7 @@ end Perun.UpdateMission = function() -- Main function for mission information updates Perun.MissionData=DCS.getCurrentMission() + -- Perun.Send(4,Perun.MissionData) end Perun.LogChat = function(playerID,msg,all) @@ -655,11 +678,7 @@ end -- ########### Finalize and set callbacks ########### if Perun.IsServer then - Perun.UDP = assert(Perun.socket.udp()) - Perun.UDP:settimeout(0) - Perun.UDP:setsockname("*", Perun.UDPSourcePort) - Perun.UDP:setpeername("127.0.0.1",Perun.UDPTargetPort) - DCS.setUserCallbacks(Perun) - net.log("Loaded - Perun - VladMordock - " .. Perun.Version ) + net.log("Perun by VladMordock was loaded: " .. Perun.Version ) + Perun.ConnectToPerun() end diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index d1e4c80..dbe0f35 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -63,10 +63,11 @@ internal class TCPController Console.WriteLine("TCP: Waiting for packet"); TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages + //tcpClient.ReceiveBufferSize = 65534; while (tcpClient.Connected && !TCPController.boolDone) //while the client is connected, we look for incoming messages { - arrReceiveByteArray = new byte[1024]; //the messages arrive as byte array + arrReceiveByteArray = new byte[65534]; //the messages arrive as byte array ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); Console.WriteLine("Sender: {0} Payload: {1}", null, strReceivedData); diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index fbaee8e..7dc1eec 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -9,7 +9,7 @@ namespace Perun_v1 public partial class form_Main : Form { // Variable definitions - public string[] arrSendBuffer = new string[100]; // Mysql send buffer + public string[] arrSendBuffer = new string[65534]; // Mysql send buffer public bool boolLetMeOut = false; // Helper to handle system tray // ################################ Main ################################ From 69501b4623dadb818aae3388e9120dc9a685a1f4 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 12:28:40 +0200 Subject: [PATCH 08/27] WIP --- 01_DCS/Hooks/Perun.lua | 5 ++-- .../Perun_v1/01_Classes/TCPController.cs | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/01_DCS/Hooks/Perun.lua b/01_DCS/Hooks/Perun.lua index 07c84d0..5a9228f 100644 --- a/01_DCS/Hooks/Perun.lua +++ b/01_DCS/Hooks/Perun.lua @@ -11,7 +11,7 @@ Perun.RefreshStatus = 15 -- (int) base refresh rate in seconds to se Perun.RefreshMission = 60 -- (int) refresh rate in seconds to send mission information (values lower than 60 may affect performance!) Perun.TCPTargetPort = 48620 -- (int) TCP port to send data to Perun.TCPPerunHost = "localhost" -- (string) IP adress of the Perun instance or "localhost" -Perun.Instance = 2 -- (int) Id number of instance (if multiple DCS instances are to run at the same PC) +Perun.Instance = 1 -- (int) Id number of instance (if multiple DCS instances are to run at the same PC) Perun.JsonStatusLocation = "Scripts\\Json\\" -- (string) folder relative do user's SaveGames DCS folder -> status file updated each RefreshMission Perun.MOTD_L1 = "Witamy na serwerze Gildia.org !" -- (string) Message send to players connecting the server - Line 1 Perun.MOTD_L2 = "Wymagamy obecnosci DCS SRS oraz TeamSpeak - szczegoly na forum" -- (string) Message send to players connecting the server - Line 2 @@ -172,7 +172,8 @@ Perun.ConnectToPerun = function () end Perun.SendPacket = function (data_id,temp) - _, err = Perun.TCP:send(temp) + _, err = Perun.TCP:send(temp) + if err then Perun.AddLog("Packed drop " .. data_id .. ", error: " .. err) Perun.ConnectToPerun() diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index dbe0f35..bfdc889 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -64,12 +64,30 @@ internal class TCPController TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages //tcpClient.ReceiveBufferSize = 65534; - + while (tcpClient.Connected && !TCPController.boolDone) //while the client is connected, we look for incoming messages { - arrReceiveByteArray = new byte[65534]; //the messages arrive as byte array - ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client - strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); + //arrReceiveByteArray = new byte[tcpClient.ReceiveBufferSize]; //the messages arrive as byte array + //ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client + //strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); + + StringBuilder CompleteMessage = new StringBuilder(); + + if (ns.CanRead) + { + byte[] ReadBuffer = new byte[1024]; + CompleteMessage = new StringBuilder(); + int numberOfBytesRead = 0; + + // Incoming message may be larger than the buffer size. + do + { + numberOfBytesRead = ns.Read(ReadBuffer, 0, ReadBuffer.Length); + CompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(ReadBuffer, 0, numberOfBytesRead)); + } + while (ns.DataAvailable); + } + strReceivedData = CompleteMessage.ToString(); Console.WriteLine("Sender: {0} Payload: {1}", null, strReceivedData); dynamic dynamicRawTCPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame From 74e227ae2724a5eef9f8fe8a93c76d060f005db9 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 12:32:05 +0200 Subject: [PATCH 09/27] VS projecy update to 8.0.0 --- .../Perun_v1/01_Classes/UDPController.cs | 91 ------------------- 02_Windows_App/Perun_v1/Perun_v1.csproj | 6 +- .../Perun_v1/Properties/AssemblyInfo.cs | 4 +- 3 files changed, 5 insertions(+), 96 deletions(-) delete mode 100644 02_Windows_App/Perun_v1/01_Classes/UDPController.cs diff --git a/02_Windows_App/Perun_v1/01_Classes/UDPController.cs b/02_Windows_App/Perun_v1/01_Classes/UDPController.cs deleted file mode 100644 index 1dc1375..0000000 --- a/02_Windows_App/Perun_v1/01_Classes/UDPController.cs +++ /dev/null @@ -1,91 +0,0 @@ -// This class handles UDP communication -using Newtonsoft.Json; -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Windows.Forms; - -internal class UDPController -{ - // Main class for UDP listener - public static int intListenPort; // Port to listen at - public static bool boolDone; // Helper to exit main loop without killing thread - public static UdpClient udpListener; // Listener object - public static string[] arrLogHistory; // Log history for GUI - public static string[] arrSendBuffer; // Mysql send buffer - public static Thread thrUDPListener; // Seperate thread for UDP - - public static void Create(int intListenPort, ref string[] arrLogHistory, ref string[] arrSendBuffer) - { - // Create class - UDPController.intListenPort = intListenPort; - UDPController.arrLogHistory = arrLogHistory; - UDPController.arrSendBuffer = arrSendBuffer; - } - - public static void StopListen() - { - // FInish listening - UDPController.boolDone = true; - UDPController.udpListener.Close(); - UDPController.udpListener = null; - - for (int i = 0; i < arrSendBuffer.Length - 1; i++) - { - arrSendBuffer[i] = null; - } - - } - - public static void StartListen() - { - Console.WriteLine("UDP Listen start"); - try - { - // Start listening to UDP - - udpListener = new UdpClient(intListenPort); - IPEndPoint ipendpointGroupEP = new IPEndPoint(IPAddress.Loopback, intListenPort); - string strReceivedData; - byte[] arrReceiveByteArray; - - // Start the main loop - UDPController.boolDone = false; - while (!UDPController.boolDone) - { - // Start listening - Console.WriteLine("UDP: Waiting for packet"); - arrReceiveByteArray = udpListener.Receive(ref ipendpointGroupEP); - strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); - Console.WriteLine("Sender: {0} Payload: {1}", ipendpointGroupEP.ToString(), strReceivedData); - - // Add to log history and rotate - dynamic dynamicRawUDPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame - string strRawUDPFrameType = dynamicRawUDPFrame.type; - PerunHelper.LogHistoryAdd(ref arrLogHistory, "UDP packet received, type: " + strRawUDPFrameType); - - // Add to mySQL send buffer (find first empty slot) - for (int i = 0; i < arrSendBuffer.Length - 1; i++) - { - if (arrSendBuffer[i] == null) - { - arrSendBuffer[i] = strReceivedData; - break; - } - } - } - udpListener.Close(); // Close port - } - catch (Exception e) - { - // General exception found - if (e.HResult != -2147467259) { - Console.WriteLine(e.ToString()); - PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR UDP - port may be in use"); - } - } - Console.WriteLine("UDP listen stop"); - } -} \ No newline at end of file diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index 4422c04..9d79445 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -13,6 +13,7 @@ true true true + ftp://s18.mydevil.net/perun/ true Web @@ -33,12 +34,11 @@ true Perun.htm 7 - 0.7.0.%2a + 0.8.0.%2a false true true true - AnyCPU @@ -171,7 +171,7 @@ False - Microsoft .NET Framework 4.6.1 %28x86 i x64%29 + Microsoft .NET Framework 4.6.1 %28x86 and x64%29 true diff --git a/02_Windows_App/Perun_v1/Properties/AssemblyInfo.cs b/02_Windows_App/Perun_v1/Properties/AssemblyInfo.cs index 315e778..ef8e214 100644 --- a/02_Windows_App/Perun_v1/Properties/AssemblyInfo.cs +++ b/02_Windows_App/Perun_v1/Properties/AssemblyInfo.cs @@ -33,7 +33,7 @@ using System.Runtime.InteropServices; // Możesz określić wszystkie wartości lub użyć domyślnych numerów kompilacji i poprawki // przy użyciu symbolu „*”, tak jak pokazano poniżej: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.8.0.0")] +[assembly: AssemblyFileVersion("0.8.0.0")] [assembly: NeutralResourcesLanguage("en")] From 4b975b18922e22ab6bf430bcb93ab6209c7594ca Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 12:43:36 +0200 Subject: [PATCH 10/27] Added tango theme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 035485b..bba42d8 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,10 @@ Core: * [Notepad++](https://notepad-plus-plus.org/) * [TortoiseGit](https://tortoisegit.org/) +## used 3rd party resources + +* [Tango Icon Library](http://tango.freedesktop.org/Tango_Icon_Library) + ## Contributing Please contact me if you'd like to contribute. From 97a4c0aa45dea780beaccec910bf7f7a1d5250c6 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 12:43:57 +0200 Subject: [PATCH 11/27] Added connection status icons --- .../Perun_v1/02_Forms/form_Main.Designer.cs | 64 +++++++++++++++++-- 02_Windows_App/Perun_v1/Perun_v1.csproj | 1 - 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs index 2994e97..ee6e051 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs @@ -65,10 +65,18 @@ this.con_txt_dcs_instance = new System.Windows.Forms.MaskedTextBox(); this.label7 = new System.Windows.Forms.Label(); this.con_txt_dcs_server_port = new System.Windows.Forms.MaskedTextBox(); + this.con_img_db = new System.Windows.Forms.PictureBox(); + this.con_img_dcs = new System.Windows.Forms.PictureBox(); + this.con_img_srs = new System.Windows.Forms.PictureBox(); + this.con_img_lotATC = new System.Windows.Forms.PictureBox(); this.con_GroupBox_1.SuspendLayout(); this.con_GroupBox_2.SuspendLayout(); this.con_GroupBox_3.SuspendLayout(); this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_db)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_dcs)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_srs)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_lotATC)).BeginInit(); this.SuspendLayout(); // // con_List_Received @@ -76,7 +84,7 @@ this.con_List_Received.Enabled = false; this.con_List_Received.FormattingEnabled = true; this.con_List_Received.Items.AddRange(new object[] { - "Welcome to Perun for DCS World!"}); + "Not connected"}); this.con_List_Received.Location = new System.Drawing.Point(6, 19); this.con_List_Received.Name = "con_List_Received"; this.con_List_Received.Size = new System.Drawing.Size(307, 147); @@ -84,7 +92,7 @@ // // con_Button_Listen_ON // - this.con_Button_Listen_ON.Location = new System.Drawing.Point(12, 519); + this.con_Button_Listen_ON.Location = new System.Drawing.Point(12, 553); this.con_Button_Listen_ON.Name = "con_Button_Listen_ON"; this.con_Button_Listen_ON.Size = new System.Drawing.Size(86, 39); this.con_Button_Listen_ON.TabIndex = 2; @@ -95,7 +103,7 @@ // con_Button_Listen_OFF // this.con_Button_Listen_OFF.Enabled = false; - this.con_Button_Listen_OFF.Location = new System.Drawing.Point(104, 519); + this.con_Button_Listen_OFF.Location = new System.Drawing.Point(104, 553); this.con_Button_Listen_OFF.Name = "con_Button_Listen_OFF"; this.con_Button_Listen_OFF.Size = new System.Drawing.Size(86, 39); this.con_Button_Listen_OFF.TabIndex = 3; @@ -106,7 +114,7 @@ // con_GroupBox_1 // this.con_GroupBox_1.Controls.Add(this.con_List_Received); - this.con_GroupBox_1.Location = new System.Drawing.Point(12, 335); + this.con_GroupBox_1.Location = new System.Drawing.Point(12, 369); this.con_GroupBox_1.Name = "con_GroupBox_1"; this.con_GroupBox_1.Size = new System.Drawing.Size(324, 176); this.con_GroupBox_1.TabIndex = 4; @@ -270,7 +278,7 @@ // // con_Button_Quit // - this.con_Button_Quit.Location = new System.Drawing.Point(251, 519); + this.con_Button_Quit.Location = new System.Drawing.Point(251, 553); this.con_Button_Quit.Name = "con_Button_Quit"; this.con_Button_Quit.Size = new System.Drawing.Size(86, 39); this.con_Button_Quit.TabIndex = 7; @@ -375,11 +383,47 @@ this.con_txt_dcs_server_port.Size = new System.Drawing.Size(207, 20); this.con_txt_dcs_server_port.TabIndex = 3; // + // con_img_db + // + this.con_img_db.Location = new System.Drawing.Point(12, 335); + this.con_img_db.Name = "con_img_db"; + this.con_img_db.Size = new System.Drawing.Size(29, 28); + this.con_img_db.TabIndex = 10; + this.con_img_db.TabStop = false; + // + // con_img_dcs + // + this.con_img_dcs.Location = new System.Drawing.Point(47, 335); + this.con_img_dcs.Name = "con_img_dcs"; + this.con_img_dcs.Size = new System.Drawing.Size(29, 28); + this.con_img_dcs.TabIndex = 11; + this.con_img_dcs.TabStop = false; + // + // con_img_srs + // + this.con_img_srs.Location = new System.Drawing.Point(82, 335); + this.con_img_srs.Name = "con_img_srs"; + this.con_img_srs.Size = new System.Drawing.Size(29, 28); + this.con_img_srs.TabIndex = 12; + this.con_img_srs.TabStop = false; + // + // con_img_lotATC + // + this.con_img_lotATC.Location = new System.Drawing.Point(117, 335); + this.con_img_lotATC.Name = "con_img_lotATC"; + this.con_img_lotATC.Size = new System.Drawing.Size(29, 28); + this.con_img_lotATC.TabIndex = 13; + this.con_img_lotATC.TabStop = false; + // // form_Main // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(349, 570); + this.ClientSize = new System.Drawing.Size(349, 604); + this.Controls.Add(this.con_img_lotATC); + this.Controls.Add(this.con_img_srs); + this.Controls.Add(this.con_img_dcs); + this.Controls.Add(this.con_img_db); this.Controls.Add(this.groupBox1); this.Controls.Add(this.con_GroupBox_3); this.Controls.Add(this.label5); @@ -405,6 +449,10 @@ this.con_GroupBox_3.PerformLayout(); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_db)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_dcs)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_srs)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_lotATC)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -447,6 +495,10 @@ private System.Windows.Forms.Label label7; private System.Windows.Forms.Label label8; private System.Windows.Forms.MaskedTextBox con_txt_dcs_instance; + private System.Windows.Forms.PictureBox con_img_db; + private System.Windows.Forms.PictureBox con_img_dcs; + private System.Windows.Forms.PictureBox con_img_srs; + private System.Windows.Forms.PictureBox con_img_lotATC; } } diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index 9d79445..092ef7c 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -124,7 +124,6 @@ - From ddb2527eb80800ed9213861a0facc99b4e2e97b2 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 13:30:44 +0200 Subject: [PATCH 12/27] Added icon resources --- .../Perun_v1/Properties/Resources.Designer.cs | 50 ++++++++++++++++++ .../Perun_v1/Properties/Resources.resx | 16 ++++++ 02_Windows_App/Perun_v1/Resources/ico_db.png | Bin 0 -> 8447 bytes .../Perun_v1/Resources/ico_error.png | Bin 0 -> 7220 bytes .../Perun_v1/Resources/ico_game.png | Bin 0 -> 8330 bytes .../Perun_v1/Resources/ico_lotatc.png | Bin 0 -> 20030 bytes 02_Windows_App/Perun_v1/Resources/ico_srs.png | Bin 0 -> 9394 bytes 02_Windows_App/Perun_v1/Resources/img_db.png | Bin 0 -> 233 bytes 8 files changed, 66 insertions(+) create mode 100644 02_Windows_App/Perun_v1/Resources/ico_db.png create mode 100644 02_Windows_App/Perun_v1/Resources/ico_error.png create mode 100644 02_Windows_App/Perun_v1/Resources/ico_game.png create mode 100644 02_Windows_App/Perun_v1/Resources/ico_lotatc.png create mode 100644 02_Windows_App/Perun_v1/Resources/ico_srs.png create mode 100644 02_Windows_App/Perun_v1/Resources/img_db.png diff --git a/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs b/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs index f337db3..5736650 100644 --- a/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs +++ b/02_Windows_App/Perun_v1/Properties/Resources.Designer.cs @@ -59,5 +59,55 @@ namespace Perun_v1.Properties { resourceCulture = value; } } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ico_db { + get { + object obj = ResourceManager.GetObject("ico_db", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ico_error { + get { + object obj = ResourceManager.GetObject("ico_error", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ico_game { + get { + object obj = ResourceManager.GetObject("ico_game", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ico_lotatc { + get { + object obj = ResourceManager.GetObject("ico_lotatc", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ico_srs { + get { + object obj = ResourceManager.GetObject("ico_srs", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } } } diff --git a/02_Windows_App/Perun_v1/Properties/Resources.resx b/02_Windows_App/Perun_v1/Properties/Resources.resx index 1af7de1..3bef010 100644 --- a/02_Windows_App/Perun_v1/Properties/Resources.resx +++ b/02_Windows_App/Perun_v1/Properties/Resources.resx @@ -117,4 +117,20 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\ico_db.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ico_error.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ico_game.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ico_lotatc.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ico_srs.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/02_Windows_App/Perun_v1/Resources/ico_db.png b/02_Windows_App/Perun_v1/Resources/ico_db.png new file mode 100644 index 0000000000000000000000000000000000000000..fb784649ca7c8d25cc7ed96cd20ff1e383b67737 GIT binary patch literal 8447 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 literal 0 HcmV?d00001 diff --git a/02_Windows_App/Perun_v1/Resources/ico_error.png b/02_Windows_App/Perun_v1/Resources/ico_error.png new file mode 100644 index 0000000000000000000000000000000000000000..cd9246a086959ae148ab6f41fd09b0f9fabd45b6 GIT binary patch literal 7220 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 literal 0 HcmV?d00001 diff --git a/02_Windows_App/Perun_v1/Resources/ico_game.png b/02_Windows_App/Perun_v1/Resources/ico_game.png new file mode 100644 index 0000000000000000000000000000000000000000..d906fde6d0a2251540bf765ab78a6a9959439c2b GIT binary patch literal 8330 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

pjC* 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

kQqi2(5-jg9e=5H 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 literal 0 HcmV?d00001 diff --git a/02_Windows_App/Perun_v1/Resources/img_db.png b/02_Windows_App/Perun_v1/Resources/img_db.png new file mode 100644 index 0000000000000000000000000000000000000000..3e9d6ed41b4901ee2e3811ef6e85df0978acf1d2 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@H!x2AA6$+S6}hN-9%vmdKI;Vst04O9%8~^|S literal 0 HcmV?d00001 From 238f6e29ae7e51d1794dbb65b9b76bd8f73513e5 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 13:31:03 +0200 Subject: [PATCH 13/27] Working mysql connection icon --- .../Perun_v1/01_Classes/DatabaseController.cs | 14 ++-- 02_Windows_App/Perun_v1/01_Classes/Globals.cs | 7 +- .../Perun_v1/01_Classes/TCPController.cs | 5 +- .../Perun_v1/02_Forms/form_Main.Designer.cs | 65 ++++++++++--------- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 32 +++++---- 02_Windows_App/Perun_v1/Perun_v1.csproj | 6 ++ 6 files changed, 76 insertions(+), 53 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs b/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs index d48beb4..0478575 100644 --- a/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs @@ -3,11 +3,13 @@ using MySql.Data.MySqlClient; using Newtonsoft.Json; using System; -internal class DatabaseController +public class DatabaseController { - public static string strMySQLConnectionString; // MySQL connection string + public string strMySQLConnectionString; // MySQL connection string + public MySqlConnection connMySQL; + public bool bStatus; - public static void SendToMySql(string strRawUDPFrame) + public void SendToMySql(string strRawUDPFrame) { // Main function to send data to mysql dynamic strUDPFrame = JsonConvert.DeserializeObject(strRawUDPFrame); // Deserialize raw data @@ -84,12 +86,12 @@ internal class DatabaseController } // Connect to mysql and execute sql - MySqlConnection connMySQL = new MySqlConnection(DatabaseController.strMySQLConnectionString); + connMySQL = new MySqlConnection(strMySQLConnectionString); try { Console.WriteLine("Sending data to MySQL - Begin"); connMySQL.Open(); - + bStatus = true; MySqlCommand cmdMySQL = new MySqlCommand(strSQLQueryTxt, connMySQL); MySqlDataReader rdrMySQL = cmdMySQL.ExecuteReader(); @@ -105,6 +107,7 @@ internal class DatabaseController // General exception found Console.WriteLine(a_ex.ToString()); PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType); + bStatus = false; } catch (MySqlException m_ex) { @@ -122,6 +125,7 @@ internal class DatabaseController PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - " + m_ex.Number); break; } + bStatus = false; } connMySQL.Close(); Console.WriteLine("Sending data to MySQL - Done"); diff --git a/02_Windows_App/Perun_v1/01_Classes/Globals.cs b/02_Windows_App/Perun_v1/01_Classes/Globals.cs index 2ccb6ec..8dc2cf2 100644 --- a/02_Windows_App/Perun_v1/01_Classes/Globals.cs +++ b/02_Windows_App/Perun_v1/01_Classes/Globals.cs @@ -1,7 +1,10 @@ -// This class gathers all global variables +// This class gathers all global variable +using MySql.Data.MySqlClient; internal class Globals { public static string strPerunVersion = "DEBUG"; // Helper for pulling version definition public static string[] arrLogHistory = new string[10]; // Log history for GUI -} \ No newline at end of file + +} + diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index bfdc889..e093bca 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -46,12 +46,9 @@ internal class TCPController { try { - // Start listening to UDP - + // Start listening to TCP tcpServer = new TcpListener(IPAddress.Any, intListenPort); - string strReceivedData; - byte[] arrReceiveByteArray; // Start the main loop TCPController.boolDone = false; diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs index ee6e051..6ff0e75 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs @@ -65,18 +65,18 @@ this.con_txt_dcs_instance = new System.Windows.Forms.MaskedTextBox(); this.label7 = new System.Windows.Forms.Label(); this.con_txt_dcs_server_port = new System.Windows.Forms.MaskedTextBox(); - this.con_img_db = new System.Windows.Forms.PictureBox(); - this.con_img_dcs = new System.Windows.Forms.PictureBox(); - this.con_img_srs = new System.Windows.Forms.PictureBox(); this.con_img_lotATC = new System.Windows.Forms.PictureBox(); + this.con_img_srs = new System.Windows.Forms.PictureBox(); + this.con_img_dcs = new System.Windows.Forms.PictureBox(); + this.con_img_db = new System.Windows.Forms.PictureBox(); this.con_GroupBox_1.SuspendLayout(); this.con_GroupBox_2.SuspendLayout(); this.con_GroupBox_3.SuspendLayout(); this.groupBox1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.con_img_db)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.con_img_dcs)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.con_img_srs)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.con_img_lotATC)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_srs)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_dcs)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_db)).BeginInit(); this.SuspendLayout(); // // con_List_Received @@ -383,37 +383,42 @@ this.con_txt_dcs_server_port.Size = new System.Drawing.Size(207, 20); this.con_txt_dcs_server_port.TabIndex = 3; // - // con_img_db + // con_img_lotATC // - this.con_img_db.Location = new System.Drawing.Point(12, 335); - this.con_img_db.Name = "con_img_db"; - this.con_img_db.Size = new System.Drawing.Size(29, 28); - this.con_img_db.TabIndex = 10; - this.con_img_db.TabStop = false; - // - // con_img_dcs - // - this.con_img_dcs.Location = new System.Drawing.Point(47, 335); - this.con_img_dcs.Name = "con_img_dcs"; - this.con_img_dcs.Size = new System.Drawing.Size(29, 28); - this.con_img_dcs.TabIndex = 11; - this.con_img_dcs.TabStop = false; + this.con_img_lotATC.Location = new System.Drawing.Point(307, 335); + this.con_img_lotATC.Name = "con_img_lotATC"; + this.con_img_lotATC.Size = new System.Drawing.Size(29, 28); + this.con_img_lotATC.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.con_img_lotATC.TabIndex = 13; + this.con_img_lotATC.TabStop = false; // // con_img_srs // - this.con_img_srs.Location = new System.Drawing.Point(82, 335); + this.con_img_srs.Location = new System.Drawing.Point(272, 335); this.con_img_srs.Name = "con_img_srs"; this.con_img_srs.Size = new System.Drawing.Size(29, 28); + this.con_img_srs.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; this.con_img_srs.TabIndex = 12; this.con_img_srs.TabStop = false; // - // con_img_lotATC + // con_img_dcs // - this.con_img_lotATC.Location = new System.Drawing.Point(117, 335); - this.con_img_lotATC.Name = "con_img_lotATC"; - this.con_img_lotATC.Size = new System.Drawing.Size(29, 28); - this.con_img_lotATC.TabIndex = 13; - this.con_img_lotATC.TabStop = false; + this.con_img_dcs.Location = new System.Drawing.Point(237, 335); + this.con_img_dcs.Name = "con_img_dcs"; + this.con_img_dcs.Size = new System.Drawing.Size(29, 28); + this.con_img_dcs.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.con_img_dcs.TabIndex = 11; + this.con_img_dcs.TabStop = false; + // + // con_img_db + // + this.con_img_db.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.con_img_db.Location = new System.Drawing.Point(202, 335); + this.con_img_db.Name = "con_img_db"; + this.con_img_db.Size = new System.Drawing.Size(29, 28); + this.con_img_db.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.con_img_db.TabIndex = 10; + this.con_img_db.TabStop = false; // // form_Main // @@ -449,10 +454,10 @@ this.con_GroupBox_3.PerformLayout(); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.con_img_db)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.con_img_dcs)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.con_img_srs)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.con_img_lotATC)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_srs)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_dcs)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.con_img_db)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index 7dc1eec..11d2797 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Drawing; using System.Threading; using System.Windows.Forms; using Newtonsoft.Json; @@ -11,6 +12,7 @@ namespace Perun_v1 // Variable definitions public string[] arrSendBuffer = new string[65534]; // Mysql send buffer public bool boolLetMeOut = false; // Helper to handle system tray + public DatabaseController dbConnection = new DatabaseController(); // ################################ Main ################################ private void form_Main_Load(object sender, EventArgs e) @@ -94,7 +96,7 @@ namespace Perun_v1 con_txt_mysql_database.Enabled = true; con_txt_mysql_username.Enabled = true; con_txt_mysql_password.Enabled = true; - //con_txt_mysql_port.Enabled = true; // TBD - protect against writting text in the port field + con_txt_mysql_port.Enabled = true; con_txt_mysql_server.Enabled = true; con_txt_3rd_lotatc.Enabled = true; con_txt_3rd_srs.Enabled = true; @@ -109,12 +111,7 @@ namespace Perun_v1 private void con_Button_Listen_ON_Click(object sender, EventArgs e) { // Start listening - //UDPController.Create(48620, ref Globals.arrLogHistory, ref arrSendBuffer); - //UDPController.thrUDPListener = new Thread(UDPController.StartListen); - //UDPController.thrUDPListener.Start(); - //UDPController.thrUDPListener.Name = "UDPThread"; - - TCPController.Create(48620, ref Globals.arrLogHistory, ref arrSendBuffer); + TCPController.Create(Int32.Parse(con_txt_dcs_server_port.Text), ref Globals.arrLogHistory, ref arrSendBuffer); TCPController.thrTCPListener = new Thread(TCPController.StartListen); TCPController.thrTCPListener.Start(); TCPController.thrTCPListener.Name = "TCPThread"; @@ -123,7 +120,7 @@ namespace Perun_v1 form_Main_SaveSettings(); // Save settings // Prepare connection string - DatabaseController.strMySQLConnectionString = "server=" + con_txt_mysql_server.Text + ";user=" + con_txt_mysql_username.Text + ";database=" + con_txt_mysql_database.Text + ";port=" + con_txt_mysql_port.Text + ";password=" + con_txt_mysql_password.Text; + dbConnection.strMySQLConnectionString = "server=" + con_txt_mysql_server.Text + ";user=" + con_txt_mysql_username.Text + ";database=" + con_txt_mysql_database.Text + ";port=" + con_txt_mysql_port.Text + ";password=" + con_txt_mysql_password.Text; // Start timmers tim_200ms.Enabled = true; @@ -136,7 +133,6 @@ namespace Perun_v1 // Stop listening try { - //UDPController.StopListen(); TCPController.StopListen(); } catch (Exception ex) @@ -283,10 +279,22 @@ namespace Perun_v1 { if (arrSendBuffer[i] != null) { - DatabaseController.SendToMySql(arrSendBuffer[i]); + dbConnection.SendToMySql(arrSendBuffer[i]); arrSendBuffer[i] = null; } } + + // Update icons + if (dbConnection.bStatus) + { + con_img_db.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_db"); + } else + { + con_img_db.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_error"); + } + con_img_dcs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_game"); + con_img_srs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_srs"); + con_img_lotATC.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_lotatc"); } private void tim_10000ms_Tick(object sender, EventArgs e) @@ -361,7 +369,7 @@ namespace Perun_v1 { strSRSJson = "{'type':'100','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'true'}}"; } - DatabaseController.SendToMySql(strSRSJson); + dbConnection.SendToMySql(strSRSJson); // Handle LotATC - TBD clean code for multiinstance if (con_check_3rd_lotatc.Checked) @@ -386,7 +394,7 @@ namespace Perun_v1 { strLotATCJson = "{'type':'101','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'true'}}"; // No LotATC controller connected } - DatabaseController.SendToMySql(strLotATCJson); + dbConnection.SendToMySql(strLotATCJson); } } } diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index 092ef7c..857d2d4 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -181,6 +181,12 @@ + + + + + + From 9d42ccc1d495b67608e7f7d70150c9aac2b60478 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 15:13:12 +0200 Subject: [PATCH 14/27] General cleanup --- .../Perun_v1/01_Classes/DatabaseController.cs | 86 ++++++++++-------- 02_Windows_App/Perun_v1/01_Classes/Program.cs | 1 - .../Perun_v1/01_Classes/TCPController.cs | 91 +++++++++++-------- .../Perun_v1/02_Forms/form_Main.Designer.cs | 5 +- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 91 +++++++++++++------ 02_Windows_App/Perun_v1/Perun_v1.csproj | 2 +- 6 files changed, 165 insertions(+), 111 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs b/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs index 0478575..3900a07 100644 --- a/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/DatabaseController.cs @@ -16,9 +16,9 @@ public class DatabaseController string strUDPFrameType = strUDPFrame.type; string strUDPFrameTimestamp = strUDPFrame.timestamp; string strUDPFrameInstance = strUDPFrame.instance; - string strUDPFramePayload = ""; - string strUDPFramePayload_Perun = ""; - string strSQLQueryTxt = ""; + string strUDPFramePayload; + string strUDPFramePayload_Perun; + string strSQLQueryTxt; // Some frames may come without timestamp, use database currrent timestampe then @@ -86,48 +86,58 @@ public class DatabaseController } // Connect to mysql and execute sql - connMySQL = new MySqlConnection(strMySQLConnectionString); try { - Console.WriteLine("Sending data to MySQL - Begin"); - connMySQL.Open(); - bStatus = true; - MySqlCommand cmdMySQL = new MySqlCommand(strSQLQueryTxt, connMySQL); - MySqlDataReader rdrMySQL = cmdMySQL.ExecuteReader(); + connMySQL = new MySqlConnection(strMySQLConnectionString); - while (rdrMySQL.Read()) + try { - Console.WriteLine(rdrMySQL[0] + " -- " + rdrMySQL[1]); + Console.WriteLine("Sending data to MySQL - Begin"); + connMySQL.Open(); + bStatus = true; + MySqlCommand cmdMySQL = new MySqlCommand(strSQLQueryTxt, connMySQL); + MySqlDataReader rdrMySQL = cmdMySQL.ExecuteReader(); + + while (rdrMySQL.Read()) + { + Console.WriteLine(rdrMySQL[0] + " -- " + rdrMySQL[1]); + } + rdrMySQL.Close(); + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + strUDPFrameInstance + " > MySQL updated, package type: " + strUDPFrameType); } - rdrMySQL.Close(); - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#"+strUDPFrameInstance + " > MySQL updated, package type: " + strUDPFrameType); - } - catch (ArgumentException a_ex) - { - // General exception found - Console.WriteLine(a_ex.ToString()); - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType); - bStatus = false; - } - catch (MySqlException m_ex) - { - // MySQL exception found - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType); - switch (m_ex.Number) + catch (ArgumentException a_ex) { - case 1042: // Unable to connect to any of the specified MySQL hosts (Check Server,Port) - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - unable to connect"); - break; - case 0: // Access denied (Check DB name,username,password) - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - access denied"); - break; - default: - PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - " + m_ex.Number); - break; + // General exception found + Console.WriteLine(a_ex.ToString()); + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType); + bStatus = false; } - bStatus = false; + catch (MySqlException m_ex) + { + // MySQL exception found + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType); + switch (m_ex.Number) + { + case 1042: // Unable to connect to any of the specified MySQL hosts (Check Server,Port) + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - unable to connect"); + break; + case 0: // Access denied (Check DB name,username,password) + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - access denied"); + break; + default: + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - " + m_ex.Number); + break; + } + bStatus = false; + } + connMySQL.Close(); + Console.WriteLine("Sending data to MySQL - Done"); } - connMySQL.Close(); - Console.WriteLine("Sending data to MySQL - Done"); + catch (ArgumentException) + { + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - wrong connection parameters"); + } + + } } diff --git a/02_Windows_App/Perun_v1/01_Classes/Program.cs b/02_Windows_App/Perun_v1/01_Classes/Program.cs index 7d0dff1..59686ac 100644 --- a/02_Windows_App/Perun_v1/01_Classes/Program.cs +++ b/02_Windows_App/Perun_v1/01_Classes/Program.cs @@ -17,7 +17,6 @@ namespace Perun_v1 static void Main() { - // Only instance Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ApplicationExit += new EventHandler(Application_ApplicationExit); diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index e093bca..6ca157b 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -7,67 +7,63 @@ using System.Text; using System.Threading; using System.Windows.Forms; -internal class TCPController +public class TCPController { // Main class for TCP listener - public static int intListenPort; // Port to connect to - public static bool boolDone; // Helper to exit main loop without killing thread - public static TcpListener tcpServer; // Listener object - public static string[] arrLogHistory; // Log history for GUI - public static string[] arrSendBuffer; // Mysql send buffer - public static Thread thrTCPListener; // Seperate thread for UDP + public int intListenPort; // Port to connect to + public bool bDone; // Helper to exit main loop without killing thread + public string[] arrLogHistory; // Log history for GUI + public string[] arrSendBuffer; // Mysql send buffer + public Thread thrTCPListener; // Seperate thread for TCP + public bool bStatus; // TCP connecion status - public static void Create(int intListenPort, ref string[] arrLogHistory, ref string[] arrSendBuffer) + public void Create(int par_intListenPort, ref string[] par_arrLogHistory, ref string[] par_arrSendBuffer) { // Create class - TCPController.intListenPort = intListenPort; - TCPController.arrLogHistory = arrLogHistory; - TCPController.arrSendBuffer = arrSendBuffer; + intListenPort = par_intListenPort; + arrLogHistory = par_arrLogHistory; + arrSendBuffer = par_arrSendBuffer; + bDone = false; + bStatus = false; } - public static void StopListen() + public void StopListen() { - // FInish listening - TCPController.boolDone = true; - TCPController.tcpServer.Stop(); - TCPController.tcpServer = null; + // Finish listening + bDone = true; + bStatus = false; for (int i = 0; i < arrSendBuffer.Length - 1; i++) { arrSendBuffer[i] = null; } - } - public static void StartListen() + public void StartListen() { - Console.WriteLine("TCP Listen start"); - while (!TCPController.boolDone) + while (!bDone) { + Console.WriteLine("TCP Listen start"); + TcpListener tcpServer = new TcpListener(IPAddress.Any, intListenPort); ; // Listener object + try { // Start listening to TCP - tcpServer = new TcpListener(IPAddress.Any, intListenPort); string strReceivedData; // Start the main loop - TCPController.boolDone = false; tcpServer.Start(); - while (!TCPController.boolDone) + bStatus = true; + while (!bDone) { // Start listening Console.WriteLine("TCP: Waiting for packet"); TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages - //tcpClient.ReceiveBufferSize = 65534; - while (tcpClient.Connected && !TCPController.boolDone) //while the client is connected, we look for incoming messages + while (tcpClient.Connected && !bDone) //while the client is connected, we look for incoming messages { - //arrReceiveByteArray = new byte[tcpClient.ReceiveBufferSize]; //the messages arrive as byte array - //ns.Read(arrReceiveByteArray, 0, arrReceiveByteArray.Length); //the same networkstream reads the message sent by the client - //strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length); - StringBuilder CompleteMessage = new StringBuilder(); if (ns.CanRead) @@ -87,24 +83,33 @@ internal class TCPController strReceivedData = CompleteMessage.ToString(); Console.WriteLine("Sender: {0} Payload: {1}", null, strReceivedData); - dynamic dynamicRawTCPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame - string strRawTCPFrameType = dynamicRawTCPFrame.type; - - PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP packet received, type: " + strRawTCPFrameType); - - // Add to mySQL send buffer (find first empty slot) - for (int i = 0; i < arrSendBuffer.Length - 1; i++) + try { - if (arrSendBuffer[i] == null) + dynamic dynamicRawTCPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame + string strRawTCPFrameType = dynamicRawTCPFrame.type; + + PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP packet received, type: " + strRawTCPFrameType); + + // Add to mySQL send buffer (find first empty slot) + for (int i = 0; i < arrSendBuffer.Length - 1; i++) { - arrSendBuffer[i] = strReceivedData; - break; + if (arrSendBuffer[i] == null) + { + arrSendBuffer[i] = strReceivedData; + break; + } } } + catch(Exception e) + { + Console.WriteLine(e.ToString()); + PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP ERROR incorrect JSON"); + } } } tcpServer.Stop(); + bStatus = false; } catch (Exception e) { @@ -114,8 +119,14 @@ internal class TCPController Console.WriteLine(e.ToString()); PerunHelper.LogHistoryAdd(ref arrLogHistory, "TCP error - connection closed or port in use"); } + } - //Console.WriteLine("TCP listen stop"); + if (!(tcpServer is null)) + { + tcpServer.Stop(); + } + bStatus = false; + Console.WriteLine("TCP listen stop"); } } } diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs index 6ff0e75..36951ba 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.Designer.cs @@ -96,7 +96,7 @@ this.con_Button_Listen_ON.Name = "con_Button_Listen_ON"; this.con_Button_Listen_ON.Size = new System.Drawing.Size(86, 39); this.con_Button_Listen_ON.TabIndex = 2; - this.con_Button_Listen_ON.Text = "Connect"; + this.con_Button_Listen_ON.Text = "Start"; this.con_Button_Listen_ON.UseVisualStyleBackColor = true; this.con_Button_Listen_ON.Click += new System.EventHandler(this.con_Button_Listen_ON_Click); // @@ -107,7 +107,7 @@ this.con_Button_Listen_OFF.Name = "con_Button_Listen_OFF"; this.con_Button_Listen_OFF.Size = new System.Drawing.Size(86, 39); this.con_Button_Listen_OFF.TabIndex = 3; - this.con_Button_Listen_OFF.Text = "Disconnect"; + this.con_Button_Listen_OFF.Text = "Stop"; this.con_Button_Listen_OFF.UseVisualStyleBackColor = true; this.con_Button_Listen_OFF.Click += new System.EventHandler(this.con_Button_Listen_OFF_Click); // @@ -156,7 +156,6 @@ // // con_txt_mysql_port // - this.con_txt_mysql_port.Enabled = false; this.con_txt_mysql_port.Location = new System.Drawing.Point(106, 45); this.con_txt_mysql_port.Name = "con_txt_mysql_port"; this.con_txt_mysql_port.Size = new System.Drawing.Size(207, 20); diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index 11d2797..a9a3360 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -10,18 +10,22 @@ namespace Perun_v1 public partial class form_Main : Form { // Variable definitions - public string[] arrSendBuffer = new string[65534]; // Mysql send buffer - public bool boolLetMeOut = false; // Helper to handle system tray - public DatabaseController dbConnection = new DatabaseController(); + public string[] arrSendBuffer = new string[65534]; // MySQL send buffer + public bool bLetMeOut = false; // Helper to handle system tray + + public DatabaseController dcConnection = new DatabaseController(); // MySQL controller + public TCPController tcpcServer=new TCPController(); // TCP controller + + public bool bSRSStatus; // Use empty/default SRS status + public bool bLotATCStatus; // Use empty/default LotATC status // ################################ Main ################################ private void form_Main_Load(object sender, EventArgs e) { // Form loaded - fill controls with default values - Globals.arrLogHistory[0] = DateTime.Now.ToString("HH:mm:ss") + " > " + "Perun started"; - form_Main_LoadSettings(); // Load settings - this.Text = PerunHelper.GetAppVersion(this.Text + " - "); // Display build version in title bar + form_Main_LoadSettings(); // Load settings + this.Text = PerunHelper.GetAppVersion(this.Text + " - "); // Display build version in title bar } public form_Main() @@ -62,7 +66,6 @@ namespace Perun_v1 Properties.Settings.Default.OTHER_SRS_FILE = con_txt_3rd_srs.Text; Properties.Settings.Default.OTHER_LOTATC_USE = con_check_3rd_lotatc.Checked; Properties.Settings.Default.OTHER_SRS_USE = con_check_3rd_srs.Checked; - Properties.Settings.Default.DCS_Server_Port = Int32.Parse(con_txt_dcs_server_port.Text); Properties.Settings.Default.DCS_Instance = Int32.Parse(con_txt_dcs_instance.Text); @@ -92,7 +95,6 @@ namespace Perun_v1 // Enables controls con_Button_Listen_ON.Enabled = true; con_Button_Listen_OFF.Enabled = false; - con_txt_mysql_database.Enabled = true; con_txt_mysql_username.Enabled = true; con_txt_mysql_password.Enabled = true; @@ -104,28 +106,30 @@ namespace Perun_v1 con_check_3rd_srs.Enabled = true; con_txt_dcs_server_port.Enabled = true; con_txt_dcs_instance.Enabled = true; - } // ################################ User input ################################ private void con_Button_Listen_ON_Click(object sender, EventArgs e) { // Start listening - TCPController.Create(Int32.Parse(con_txt_dcs_server_port.Text), ref Globals.arrLogHistory, ref arrSendBuffer); - TCPController.thrTCPListener = new Thread(TCPController.StartListen); - TCPController.thrTCPListener.Start(); - TCPController.thrTCPListener.Name = "TCPThread"; + tcpcServer.Create(Int32.Parse(con_txt_dcs_server_port.Text), ref Globals.arrLogHistory, ref arrSendBuffer); + tcpcServer.thrTCPListener = new Thread(tcpcServer.StartListen); + tcpcServer.thrTCPListener.Start(); + tcpcServer.thrTCPListener.Name = "TCPThread"; - form_Main_DisableControls(); // Disable controlls - form_Main_SaveSettings(); // Save settings + form_Main_DisableControls(); // Disable controlls + form_Main_SaveSettings(); // Save settings // Prepare connection string - dbConnection.strMySQLConnectionString = "server=" + con_txt_mysql_server.Text + ";user=" + con_txt_mysql_username.Text + ";database=" + con_txt_mysql_database.Text + ";port=" + con_txt_mysql_port.Text + ";password=" + con_txt_mysql_password.Text; + dcConnection.strMySQLConnectionString = "server=" + con_txt_mysql_server.Text + ";user=" + con_txt_mysql_username.Text + ";database=" + con_txt_mysql_database.Text + ";port=" + con_txt_mysql_port.Text + ";password=" + con_txt_mysql_password.Text; // Start timmers tim_200ms.Enabled = true; tim_1000ms.Enabled = true; tim_10000ms.Enabled = true; + + // Send initial data + tim_10000ms_Tick(null, null); } private void con_Button_Listen_OFF_Click(object sender, EventArgs e) @@ -133,7 +137,7 @@ namespace Perun_v1 // Stop listening try { - TCPController.StopListen(); + tcpcServer.StopListen(); } catch (Exception ex) { @@ -142,6 +146,11 @@ namespace Perun_v1 form_Main_EnableControls(); // Enable controls + con_img_db.Image = null; + con_img_dcs.Image = null; + con_img_lotATC.Image = null; + con_img_srs.Image = null; + // Stop timmers tim_1000ms.Enabled = false; tim_10000ms.Enabled = false; @@ -194,7 +203,7 @@ namespace Perun_v1 { form_Main_SaveSettings(); - boolLetMeOut = true; // Save settings on exit + bLetMeOut = true; // Save settings on exit this.Close(); // Allow to exit application } else if (dialogResult == DialogResult.No) @@ -244,7 +253,7 @@ namespace Perun_v1 private void form_Main_FormClosing(object sender, FormClosingEventArgs e) { // Minimize to try on clicking "X" - if (e.CloseReason == CloseReason.UserClosing && !boolLetMeOut) + if (e.CloseReason == CloseReason.UserClosing && !bLetMeOut) { e.Cancel = true; form_Main_SendToTray(); // Send app to system tray @@ -279,22 +288,45 @@ namespace Perun_v1 { if (arrSendBuffer[i] != null) { - dbConnection.SendToMySql(arrSendBuffer[i]); + dcConnection.SendToMySql(arrSendBuffer[i]); arrSendBuffer[i] = null; } } - // Update icons - if (dbConnection.bStatus) + // Update status icons at main form + if (dcConnection.bStatus) { con_img_db.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_db"); } else { con_img_db.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_error"); } - con_img_dcs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_game"); - con_img_srs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_srs"); - con_img_lotATC.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_lotatc"); + if (tcpcServer.bStatus) + { + con_img_dcs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_game"); + } + else + { + con_img_dcs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_error"); + } + if (bSRSStatus) + { + con_img_srs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_srs"); + } + else + { + con_img_srs.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_error"); + } + if (bLotATCStatus) + { + con_img_lotATC.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_lotatc"); + } + else + { + con_img_lotATC.Image = (Image)Properties.Resources.ResourceManager.GetObject("ico_error"); + } + + } private void tim_10000ms_Tick(object sender, EventArgs e) @@ -356,11 +388,12 @@ namespace Perun_v1 } boolSRSdefault = false; PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > SRS data loaded"); - + bSRSStatus = true; } catch { PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > SRS data ERROR"); + bSRSStatus = false; } @@ -369,7 +402,7 @@ namespace Perun_v1 { strSRSJson = "{'type':'100','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'true'}}"; } - dbConnection.SendToMySql(strSRSJson); + dcConnection.SendToMySql(strSRSJson); // Handle LotATC - TBD clean code for multiinstance if (con_check_3rd_lotatc.Checked) @@ -382,10 +415,12 @@ namespace Perun_v1 strLotATCJson = "{'type':'101','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':'" + strLotATCJson + "'}"; boolLotATCdefault = false; PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > LotATC data loaded"); + bLotATCStatus = true; } catch { PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "#" + Int32.Parse(con_txt_dcs_instance.Text) + " > LotATC data ERROR"); + bLotATCStatus = false; } @@ -394,7 +429,7 @@ namespace Perun_v1 { strLotATCJson = "{'type':'101','instance':'" + Int32.Parse(con_txt_dcs_instance.Text) + "','payload':{'ignore':'true'}}"; // No LotATC controller connected } - dbConnection.SendToMySql(strLotATCJson); + dcConnection.SendToMySql(strLotATCJson); } } } diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index 857d2d4..6824983 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -75,7 +75,7 @@ true - true + false false From fcb189a4cdcb16101e3dfd9f93224a290a287459 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 13 Sep 2019 15:56:56 +0200 Subject: [PATCH 15/27] Reconnecting issue solved --- .../Perun_v1/01_Classes/TCPController.cs | 19 ++++++++++++++++--- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index 6ca157b..96695c4 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -41,6 +41,9 @@ public class TCPController public void StartListen() { + NetworkStream ns=null; + TcpClient tcpClient=null; + while (!bDone) { Console.WriteLine("TCP Listen start"); @@ -59,8 +62,8 @@ public class TCPController // Start listening Console.WriteLine("TCP: Waiting for packet"); - TcpClient tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it - NetworkStream ns = tcpClient.GetStream(); //networkstream is used to send/receive messages + tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it + ns = tcpClient.GetStream(); //networkstream is used to send/receive messages while (tcpClient.Connected && !bDone) //while the client is connected, we look for incoming messages { @@ -78,7 +81,7 @@ public class TCPController numberOfBytesRead = ns.Read(ReadBuffer, 0, ReadBuffer.Length); CompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(ReadBuffer, 0, numberOfBytesRead)); } - while (ns.DataAvailable); + while (ns.DataAvailable && !bDone); } strReceivedData = CompleteMessage.ToString(); Console.WriteLine("Sender: {0} Payload: {1}", null, strReceivedData); @@ -121,6 +124,16 @@ public class TCPController } } + + if (!(ns is null)) + { + ns.Flush(); + ns.Close(); + } + if (!(tcpClient is null)) + { + tcpClient.Close(); + } if (!(tcpServer is null)) { tcpServer.Stop(); diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index a9a3360..070af1d 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -112,6 +112,7 @@ namespace Perun_v1 private void con_Button_Listen_ON_Click(object sender, EventArgs e) { // Start listening + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "Opening connections"); tcpcServer.Create(Int32.Parse(con_txt_dcs_server_port.Text), ref Globals.arrLogHistory, ref arrSendBuffer); tcpcServer.thrTCPListener = new Thread(tcpcServer.StartListen); tcpcServer.thrTCPListener.Start(); @@ -135,6 +136,15 @@ namespace Perun_v1 private void con_Button_Listen_OFF_Click(object sender, EventArgs e) { // Stop listening + + // Display information + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "Closing connections"); + con_Button_Listen_OFF.Enabled = false; + timer1_Tick(null, null); + this.Refresh(); + Application.DoEvents(); + + try { tcpcServer.StopListen(); @@ -144,6 +154,10 @@ namespace Perun_v1 Console.WriteLine(ex.ToString()); } + while (tcpcServer.thrTCPListener.IsAlive) + { + Thread.Sleep(100); //ms + } form_Main_EnableControls(); // Enable controls con_img_db.Image = null; @@ -155,6 +169,10 @@ namespace Perun_v1 tim_1000ms.Enabled = false; tim_10000ms.Enabled = false; tim_200ms.Enabled = false; + + // Display information about closed connections + PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "Connections closed"); + timer1_Tick(null, null); } private void con_lab_github_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) From 09d379d6113729b2bcfb63b127eb4210f08613ab Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 4 Oct 2019 14:17:15 +0200 Subject: [PATCH 16/27] Added support for command line arguments --- 02_Windows_App/Perun_v1/01_Classes/Globals.cs | 2 +- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 33 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/Globals.cs b/02_Windows_App/Perun_v1/01_Classes/Globals.cs index 8dc2cf2..0e65acb 100644 --- a/02_Windows_App/Perun_v1/01_Classes/Globals.cs +++ b/02_Windows_App/Perun_v1/01_Classes/Globals.cs @@ -5,6 +5,6 @@ internal class Globals { public static string strPerunVersion = "DEBUG"; // Helper for pulling version definition public static string[] arrLogHistory = new string[10]; // Log history for GUI - + public static string strPerunTitleText = ""; } diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index 070af1d..0f0e169 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -24,8 +24,31 @@ namespace Perun_v1 { // Form loaded - fill controls with default values Globals.arrLogHistory[0] = DateTime.Now.ToString("HH:mm:ss") + " > " + "Perun started"; - form_Main_LoadSettings(); // Load settings - this.Text = PerunHelper.GetAppVersion(this.Text + " - "); // Display build version in title bar + + Globals.strPerunTitleText = PerunHelper.GetAppVersion(this.Text + " - "); // Display build version in title bar + this.Text = Globals.strPerunTitleText; + + form_Main_LoadSettings(); // Load settings + + // Use command line parameters + string[] args = Environment.GetCommandLineArgs(); + if (args.Length > 1) + { + // server port + if (args[1] != null) + { + con_txt_dcs_server_port.Text = args[1]; + } + } + if (args.Length > 2) + { + // instance id + if (args[2] != null) + { + con_txt_dcs_instance.Text = args[2]; + } + } + } public form_Main() @@ -131,6 +154,9 @@ namespace Perun_v1 // Send initial data tim_10000ms_Tick(null, null); + + // Set title bar + this.Text = "[#"+ con_txt_dcs_instance.Text + "] " + Globals.strPerunTitleText; } private void con_Button_Listen_OFF_Click(object sender, EventArgs e) @@ -173,6 +199,9 @@ namespace Perun_v1 // Display information about closed connections PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "Connections closed"); timer1_Tick(null, null); + + // Set title bar + this.Text = Globals.strPerunTitleText; } private void con_lab_github_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) From 35d63d072c1bf501019aac5d0f91b2135c85843b Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 4 Oct 2019 14:21:21 +0200 Subject: [PATCH 17/27] Clean up --- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index 0f0e169..fd9d4a5 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -385,7 +385,7 @@ namespace Perun_v1 bool boolSRSdefault = true; bool boolLotATCdefault = true; - // Handle SRS - TBD clean code for multiinstance + // Handle SRS if (con_check_3rd_srs.Checked) { try @@ -451,7 +451,7 @@ namespace Perun_v1 } dcConnection.SendToMySql(strSRSJson); - // Handle LotATC - TBD clean code for multiinstance + // Handle LotATC if (con_check_3rd_lotatc.Checked) { try From 5916ccedb39e33e9b3b3d51367a040245de70906 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 4 Oct 2019 14:43:43 +0200 Subject: [PATCH 18/27] Debug only - check performance --- 02_Windows_App/Perun_v1/01_Classes/TCPController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs index 96695c4..7c682a8 100644 --- a/02_Windows_App/Perun_v1/01_Classes/TCPController.cs +++ b/02_Windows_App/Perun_v1/01_Classes/TCPController.cs @@ -64,7 +64,8 @@ public class TCPController Console.WriteLine("TCP: Waiting for packet"); tcpClient = tcpServer.AcceptTcpClient(); //if a connection exists, the server will accept it ns = tcpClient.GetStream(); //networkstream is used to send/receive messages - + //ns.ReadTimeout = 100; + while (tcpClient.Connected && !bDone) //while the client is connected, we look for incoming messages { StringBuilder CompleteMessage = new StringBuilder(); From 44da46083e5f3779b5c84fbb663131999531109e Mon Sep 17 00:00:00 2001 From: szporowolik Date: Fri, 4 Oct 2019 14:48:29 +0200 Subject: [PATCH 19/27] Added command line support for srs and lotatc --- 02_Windows_App/Perun_v1/02_Forms/form_Main.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs index fd9d4a5..8bca802 100644 --- a/02_Windows_App/Perun_v1/02_Forms/form_Main.cs +++ b/02_Windows_App/Perun_v1/02_Forms/form_Main.cs @@ -48,7 +48,24 @@ namespace Perun_v1 con_txt_dcs_instance.Text = args[2]; } } - + if (args.Length > 3) + { + // srs + if (args[3] != null) + { + con_txt_3rd_srs.Text = args[3]; + con_check_3rd_srs.Checked = true; + } + } + if (args.Length > 4) + { + // lotatc + if (args[4] != null) + { + con_txt_3rd_lotatc.Text = args[4]; + con_check_3rd_lotatc.Checked = true; + } + } } public form_Main() From 22d87b8a6217c48828f413fc27e036a5afb6405c Mon Sep 17 00:00:00 2001 From: VladMordock Date: Thu, 17 Oct 2019 16:36:23 +0200 Subject: [PATCH 20/27] Update m1081_perun.sql --- 03_MySQL/m1081_perun.sql | 108 ++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/03_MySQL/m1081_perun.sql b/03_MySQL/m1081_perun.sql index 5ca711f..f7f1603 100644 --- a/03_MySQL/m1081_perun.sql +++ b/03_MySQL/m1081_perun.sql @@ -1,26 +1,13 @@ - SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET AUTOCOMMIT = 0; START TRANSACTION; SET time_zone = "+00:00"; - /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; --- --- Baza danych: `m1081_perun` --- -CREATE DATABASE IF NOT EXISTS `m1081_perun` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -USE `m1081_perun`; - --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_DataMissionHashes` --- DROP TABLE IF EXISTS `pe_DataMissionHashes`; CREATE TABLE IF NOT EXISTS `pe_DataMissionHashes` ( @@ -33,12 +20,6 @@ CREATE TABLE IF NOT EXISTS `pe_DataMissionHashes` ( KEY `pe_DataMissionHashes_instance` (`pe_DataMissionHashes_instance`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_DataPlayers` --- - DROP TABLE IF EXISTS `pe_DataPlayers`; CREATE TABLE IF NOT EXISTS `pe_DataPlayers` ( `pe_DataPlayers_id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -50,12 +31,6 @@ CREATE TABLE IF NOT EXISTS `pe_DataPlayers` ( UNIQUE KEY `UNIQUE_UCID` (`pe_DataPlayers_ucid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_DataRaw` --- - DROP TABLE IF EXISTS `pe_DataRaw`; CREATE TABLE IF NOT EXISTS `pe_DataRaw` ( `pe_dataraw_type` tinyint(4) NOT NULL, @@ -65,12 +40,6 @@ CREATE TABLE IF NOT EXISTS `pe_DataRaw` ( PRIMARY KEY (`pe_dataraw_type`,`pe_dataraw_instance`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_DataTypes` --- - DROP TABLE IF EXISTS `pe_DataTypes`; CREATE TABLE IF NOT EXISTS `pe_DataTypes` ( `pe_DataTypes_id` int(11) NOT NULL AUTO_INCREMENT, @@ -80,12 +49,6 @@ CREATE TABLE IF NOT EXISTS `pe_DataTypes` ( UNIQUE KEY `UNIQUE_TYPE_NAME` (`pe_DataTypes_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_LogChat` --- - DROP TABLE IF EXISTS `pe_LogChat`; CREATE TABLE IF NOT EXISTS `pe_LogChat` ( `pe_LogChat_id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -96,15 +59,10 @@ CREATE TABLE IF NOT EXISTS `pe_LogChat` ( `pe_LogChat_all` varchar(10) NOT NULL, PRIMARY KEY (`pe_LogChat_id`), KEY `pe_LogChat_missionhash_id` (`pe_LogChat_missionhash_id`), - KEY `pe_LogChat_playerid` (`pe_LogChat_playerid`) + KEY `pe_LogChat_playerid` (`pe_LogChat_playerid`), + KEY `pe_LogChat_datetime` (`pe_LogChat_datetime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_LogEvent` --- - DROP TABLE IF EXISTS `pe_LogEvent`; CREATE TABLE IF NOT EXISTS `pe_LogEvent` ( `pe_LogEvent_id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -115,15 +73,10 @@ CREATE TABLE IF NOT EXISTS `pe_LogEvent` ( `pe_LogEvent_arg1` varchar(150) DEFAULT NULL, `pe_LogEvent_arg2` varchar(150) DEFAULT NULL, PRIMARY KEY (`pe_LogEvent_id`), - KEY `pe_LogEvent_missionhash_id` (`pe_LogEvent_missionhash_id`) + KEY `pe_LogEvent_missionhash_id` (`pe_LogEvent_missionhash_id`), + KEY `pe_LogEvent_datetime` (`pe_LogEvent_datetime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_LogLogins` --- - DROP TABLE IF EXISTS `pe_LogLogins`; CREATE TABLE IF NOT EXISTS `pe_LogLogins` ( `pe_LogLogins_id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -133,15 +86,10 @@ CREATE TABLE IF NOT EXISTS `pe_LogLogins` ( `pe_LogLogins_name` varchar(150) NOT NULL, `pe_LogLogins_ip` varchar(100) NOT NULL, PRIMARY KEY (`pe_LogLogins_id`), - KEY `pe_LogLogins_playerid` (`pe_LogLogins_playerid`) + KEY `pe_LogLogins_playerid` (`pe_LogLogins_playerid`), + KEY `pe_LogLogins_datetime` (`pe_LogLogins_datetime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- -------------------------------------------------------- - --- --- Struktura tabeli dla tabeli `pe_LogStats` --- - DROP TABLE IF EXISTS `pe_LogStats`; CREATE TABLE IF NOT EXISTS `pe_LogStats` ( `pe_LogStats_id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -172,9 +120,51 @@ CREATE TABLE IF NOT EXISTS `pe_LogStats` ( `ps_farp_landings` int(11) UNSIGNED NOT NULL DEFAULT '0', `ps_other_landings` int(10) UNSIGNED NOT NULL DEFAULT '0', `ps_other_takeoffs` int(10) UNSIGNED NOT NULL DEFAULT '0', + `pe_LogStats_mstatus` enum('?','RTB','MIA','KIA') DEFAULT NULL, + `ps_takeoffs` int(10) UNSIGNED DEFAULT '0', + `ps_landings` int(10) UNSIGNED DEFAULT '0', + `ps_kills_AA` int(10) UNSIGNED DEFAULT '0', + `ps_kills_AG` int(10) UNSIGNED DEFAULT '0', + `ps_kills_AS` int(10) UNSIGNED DEFAULT '0', + `ps_kills_AAA` int(10) UNSIGNED DEFAULT '0', PRIMARY KEY (`pe_LogStats_id`), - UNIQUE KEY `UNIQUE_STATS_PER_MISSION_AND_UCID_AND_TYPE` (`pe_LogStats_playerid`,`pe_LogStats_missionhash_id`,`pe_LogStats_typeid`) USING BTREE + UNIQUE KEY `UNIQUE_STATS_PER_MISSION_AND_UCID_AND_TYPE` (`pe_LogStats_playerid`,`pe_LogStats_missionhash_id`,`pe_LogStats_typeid`) USING BTREE, + KEY `pe_LogStats_missionhash_id` (`pe_LogStats_missionhash_id`), + KEY `pe_LogStats_playerid` (`pe_LogStats_playerid`), + KEY `pe_LogStats_typeid` (`pe_LogStats_typeid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TRIGGER IF EXISTS `pe_LogStats_UPDATE`; +DELIMITER $$ +CREATE TRIGGER `pe_LogStats_UPDATE` BEFORE UPDATE ON `pe_LogStats` FOR EACH ROW BEGIN + + SET NEW.ps_takeoffs = NEW.ps_airfield_takeoffs + NEW.ps_farp_takeoffs + NEW.ps_other_takeoffs + NEW.ps_ship_takeoffs; + SET NEW.ps_landings = NEW.ps_airfield_landings + NEW.ps_farp_landings + NEW.ps_other_landings + NEW.ps_ship_landings; + SET NEW.ps_kills_AA = NEW.ps_kills_planes + NEW.ps_kills_helicopters; + SET NEW.ps_kills_AG = NEW.ps_kills_armor + NEW.ps_kills_unarmed + NEW.ps_kills_fortification; + SET NEW.ps_kills_AS = NEW.ps_kills_ships; + SET NEW.ps_kills_AAA = NEW.ps_kills_air_defense; + + IF NEW.ps_ejections > 0 THEN + SET NEW.pe_LogStats_mstatus = "MIA"; + ELSEIF NEW.ps_deaths > 0 THEN + SET NEW.pe_LogStats_mstatus = "KIA"; + ELSEIF NEW.ps_landings >= NEW.ps_takeoffs THEN + IF NEW.ps_takeoffs > 0 or NEW.ps_landings > 0 THEN + SET NEW.pe_LogStats_mstatus = "RTB"; + ELSE + SET NEW.pe_LogStats_mstatus = "?"; + END IF; + ELSEIF NEW.ps_takeoffs > NEW.ps_landings and NEW.ps_ejections=0 and NEW.ps_deaths=0 THEN +SET NEW.pe_LogStats_mstatus = "MIA"; + ELSE + SET NEW.pe_LogStats_mstatus = "?"; + END IF; +END +$$ +DELIMITER ; + + +ALTER TABLE `pe_DataPlayers` ADD FULLTEXT KEY `pe_DataPlayers_ucid` (`pe_DataPlayers_ucid`); COMMIT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; From a58eced7bff610ff5471d185dd67bd9d0640ff86 Mon Sep 17 00:00:00 2001 From: VladMordock Date: Thu, 17 Oct 2019 16:39:17 +0200 Subject: [PATCH 21/27] Update README.md Updates to match v0.8 release --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bba42d8..1688193 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Provided windows app puts received UDP packets to MySQL database. Additionaly Pe However, this software is intended to be used by experienced users - the output is Json data and MySQL; you will need to process/display it yourself. -![Perun in action](https://i.imgur.com/ougQMPq.png) +![Perun in action](https://i.imgur.com/vHw8Xu5.png) ![Data flow](https://i.imgur.com/sHDQoLM.png) ### Prerequisites From edc1133023246a4ba12d74ff0e454dc12b9534b2 Mon Sep 17 00:00:00 2001 From: VladMordock Date: Thu, 17 Oct 2019 17:06:13 +0200 Subject: [PATCH 22/27] Update README.md Updated readme to match v0.8 --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1688193..defb332 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ # Perun for DCS World -This toolset extracts data from DCS World server and sends information to the local Json file and UDP port for further processing. +Included lua script extracts data from DCS World multiplayer server and sends information to TCP port and JSON file for further processing. -Provided windows app puts received UDP packets to MySQL database. Additionaly Perun windows application can be used to merge LotATC and DCS SRS data in one database making Perun for DCS World wannabe ultimate integration tool for the server admins. +Provided windows app puts received TCP packets to MySQL database; additionaly Perun windows application can be used to merge LotATC and DCS SRS data in one database making Perun for DCS World wannabe ultimate integration tool for the server admins. -However, this software is intended to be used by experienced users - the output is Json data and MySQL; you will need to process/display it yourself. +However, this software is intended to be used by experienced users - the output is MySQL data and/or JSON file; you will need to process/display it yourself. ![Perun in action](https://i.imgur.com/vHw8Xu5.png) -![Data flow](https://i.imgur.com/sHDQoLM.png) +![Data flow](https://i.imgur.com/JbNu77l.png) ### Prerequisites @@ -20,7 +20,7 @@ Core: * For JSON Export: * DCS World stable or DCS World beta * **(Optional)** For MySQL Export: - * MySQL server with read/write access (tested with v5.7.21) + * MySQL database with read/write access (tested with v5.7.21) * .NET Framework 4.8.0 3rd party applications support: @@ -29,9 +29,9 @@ Core: ### Installing -* Download latest [release](https://github.com/szporwolik/perun/releases), **optionaly** together with windows binary file for MySQL export - [DOWNLOAD](http://share.porwolik.com/ftp/perun/Perun.htm) +* Download latest [release](https://github.com/szporwolik/perun/releases) * Copy contents of [01_DCS](https://github.com/szporwolik/perun/tree/master/01_DCS) to your \Scripts folder (located inside DCS folder in your Saved Games) -* **optionaly** Create MySQL server using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL) +* **optionaly** Create MySQL database using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL) * **optionaly** Run the Win32 application * set MySQL connection data * point LotATC json file location @@ -40,9 +40,9 @@ Core: * Start DCS World and host multiplayer session * by default the JSON is written into Scripts\Json folder located in your Saved Games DCS folder tree * by default the TCP port 48620 is in use as target port -* Data shall be filling your MySQL database +* Data shall now be filling your MySQL database -## Data packets +## Data packets (for expert users) * ```ID: 1```, contains version/diagnostic information * ```ID: 2```, contains status data in the following sections * mission - minimal information about mission @@ -62,7 +62,6 @@ Core: * [VisualStudio 2017 Community](https://visualstudio.microsoft.com/vs/community/) * [Notepad++](https://notepad-plus-plus.org/) -* [TortoiseGit](https://tortoisegit.org/) ## used 3rd party resources From 40302fed4b9e74720576a929c603105d320893de Mon Sep 17 00:00:00 2001 From: VladMordock Date: Thu, 17 Oct 2019 17:17:24 +0200 Subject: [PATCH 23/27] Update README.md Added information about command line arguments --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index defb332..c9da866 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,21 @@ Core: * by default the TCP port 48620 is in use as target port * Data shall now be filling your MySQL database -## Data packets (for expert users) +## Windows APP - command line arguments (for expert users) +Windows app supports command line arguments, what may be handy in case of multiple instance of DCS servers running at the same machine. + +The following arguments are accepted (keep the order!): +* server port (shall be the same as in the lua file!) +* instance ID (shall be the same as in the lua file!) +* path to SRS client-list.json +* path to LotATC stats.json + +Example for windows shortcut: +``` +C:\Perun_v1\Perun.exe 48621 1 "G:\DCS SRS\clients-list.json" "C:\Users\DCS\Saved Games\DCS\Mods\tech\LotAtc\stats.json" +``` + +## Data packets - send to TCP port (for expert users) * ```ID: 1```, contains version/diagnostic information * ```ID: 2```, contains status data in the following sections * mission - minimal information about mission From e8d3338d9ba5c91fe2d9cd8de6a5f42cd1bb5fd4 Mon Sep 17 00:00:00 2001 From: VladMordock Date: Thu, 17 Oct 2019 17:24:13 +0200 Subject: [PATCH 24/27] Update README.md Minor update of the formatting --- README.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c9da866..94f426e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ However, this software is intended to be used by experienced users - the output ![Perun in action](https://i.imgur.com/vHw8Xu5.png) ![Data flow](https://i.imgur.com/JbNu77l.png) -### Prerequisites +## Prerequisites Core: * For JSON Export: @@ -27,22 +27,24 @@ Core: * for [DCS SRS](https://github.com/ciribob/DCS-SimpleRadioStandalone/releases) integration location of the clients-list.json file will be required (by default: SRS Server folder), "Auto Export List" option has to be enabled - see [SRS documentation](https://github.com/ciribob/DCS-SimpleRadioStandalone/wiki) * for [LotATC](https://www.lotatc.com/) you will need location of stats.json file and proper LotATC configuration with JSON data export enabled - see [LotATC documentation](https://www.lotatc.com/documentation/server_configuration.html) -### Installing +## Installing * Download latest [release](https://github.com/szporwolik/perun/releases) * Copy contents of [01_DCS](https://github.com/szporwolik/perun/tree/master/01_DCS) to your \Scripts folder (located inside DCS folder in your Saved Games) -* **optionaly** Create MySQL database using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL) -* **optionaly** Run the Win32 application - * set MySQL connection data - * point LotATC json file location - * point DCS SRS json file location - * click connect and leave the app running in the background +* **optionaly** create MySQL database using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL) + +## Running * Start DCS World and host multiplayer session * by default the JSON is written into Scripts\Json folder located in your Saved Games DCS folder tree * by default the TCP port 48620 is in use as target port -* Data shall now be filling your MySQL database +* **optionaly** run the Win32 application + * set MySQL connection data + * **optionaly** point LotATC json file location + * **optionaly** point DCS SRS json file location + * click connect and leave the app running in the background + * **data shall now be filling your MySQL database** -## Windows APP - command line arguments (for expert users) +### Windows APP - command line arguments (for expert users) Windows app supports command line arguments, what may be handy in case of multiple instance of DCS servers running at the same machine. The following arguments are accepted (keep the order!): @@ -56,7 +58,8 @@ Example for windows shortcut: C:\Perun_v1\Perun.exe 48621 1 "G:\DCS SRS\clients-list.json" "C:\Users\DCS\Saved Games\DCS\Mods\tech\LotAtc\stats.json" ``` -## Data packets - send to TCP port (for expert users) +# API documentation (for expert users) +## Data packets - send from lua to TCP port * ```ID: 1```, contains version/diagnostic information * ```ID: 2```, contains status data in the following sections * mission - minimal information about mission @@ -72,6 +75,7 @@ C:\Perun_v1\Perun.exe 48621 1 "G:\DCS SRS\clients-list.json" "C:\Users\DCS\Saved * ```ID: 100```, DCS SRS's client-list.json * ```ID: 101```, LotATC's stats.json +# Project information ## Built With * [VisualStudio 2017 Community](https://visualstudio.microsoft.com/vs/community/) From 548281a3d747b17494335492b0073b60ce918ac7 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 17 Oct 2019 17:27:58 +0200 Subject: [PATCH 25/27] Updated lua script for v0.8 --- 01_DCS/Hooks/Perun.lua | 6 +++--- 01_DCS/Json/perun_status_data.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/01_DCS/Hooks/Perun.lua b/01_DCS/Hooks/Perun.lua index 5a9228f..f1f2c2e 100644 --- a/01_DCS/Hooks/Perun.lua +++ b/01_DCS/Hooks/Perun.lua @@ -9,12 +9,12 @@ package.cpath = package.cpath..";"..lfs.currentdir().."/LuaSocket/?.dll" Perun.RefreshStatus = 15 -- (int) base refresh rate in seconds to send status update (values lower than 60 may affect performance!) Perun.RefreshMission = 60 -- (int) refresh rate in seconds to send mission information (values lower than 60 may affect performance!) -Perun.TCPTargetPort = 48620 -- (int) TCP port to send data to +Perun.TCPTargetPort = 48621 -- (int) TCP port to send data to Perun.TCPPerunHost = "localhost" -- (string) IP adress of the Perun instance or "localhost" Perun.Instance = 1 -- (int) Id number of instance (if multiple DCS instances are to run at the same PC) Perun.JsonStatusLocation = "Scripts\\Json\\" -- (string) folder relative do user's SaveGames DCS folder -> status file updated each RefreshMission -Perun.MOTD_L1 = "Witamy na serwerze Gildia.org !" -- (string) Message send to players connecting the server - Line 1 -Perun.MOTD_L2 = "Wymagamy obecnosci DCS SRS oraz TeamSpeak - szczegoly na forum" -- (string) Message send to players connecting the server - Line 2 +Perun.MOTD_L1 = "Welcome to our server!" -- (string) Message send to players connecting the server - Line 1 +Perun.MOTD_L2 = "Please use SRS radio." -- (string) Message send to players connecting the server - Line 2 -- ###################### END OF SETTINGS - DO NOT MODIFY OUTSIDE THIS SECTION ###################### diff --git a/01_DCS/Json/perun_status_data.json b/01_DCS/Json/perun_status_data.json index d3f5a12..60b0742 100644 --- a/01_DCS/Json/perun_status_data.json +++ b/01_DCS/Json/perun_status_data.json @@ -1 +1 @@ - +[] From fd92b1c287d361ce5fdbf1dc9b3720e35a71d19f Mon Sep 17 00:00:00 2001 From: szporowolik Date: Thu, 17 Oct 2019 17:34:18 +0200 Subject: [PATCH 26/27] Updated readme - added information about db structure and multiinstance support within one database --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94f426e..71dd2e3 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Core: * Download latest [release](https://github.com/szporwolik/perun/releases) * Copy contents of [01_DCS](https://github.com/szporwolik/perun/tree/master/01_DCS) to your \Scripts folder (located inside DCS folder in your Saved Games) -* **optionaly** create MySQL database using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL) +* **optionaly** create MySQL database using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL); note that you need just a one database per DCS server machine - multiple instances pushing data to the one database are supported ## Running * Start DCS World and host multiplayer session @@ -59,6 +59,16 @@ C:\Perun_v1\Perun.exe 48621 1 "G:\DCS SRS\clients-list.json" "C:\Users\DCS\Saved ``` # API documentation (for expert users) +## MySQL database structure +* table: pe_DataMissionHashes - holds mission hashes, unique hashes created per each mission start at server +* table: pe_DataPlayers - holds players UCIDs together with last login information +* table: pe_DataRaw - holds raw data received from perun windows app, containing debug/version information together with DCS SRS and LotATC data +* table: pe_DataTypes - names of all model depende class names detected in DCS +* table: pe_LogChat - holds chat history +* table: pe_LogEvent - holds event history +* table: pe_LogLogins - holds login to server event history +* table: pe_LogStats - holds static information + ## Data packets - send from lua to TCP port * ```ID: 1```, contains version/diagnostic information * ```ID: 2```, contains status data in the following sections From 1438e55686ab437b535f8f138187794b2a588904 Mon Sep 17 00:00:00 2001 From: szporowolik Date: Sat, 19 Oct 2019 11:24:12 +0200 Subject: [PATCH 27/27] v8.0 build --- 02_Windows_App/Perun_v1/Perun_v1.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_Windows_App/Perun_v1/Perun_v1.csproj b/02_Windows_App/Perun_v1/Perun_v1.csproj index 6824983..69b9a78 100644 --- a/02_Windows_App/Perun_v1/Perun_v1.csproj +++ b/02_Windows_App/Perun_v1/Perun_v1.csproj @@ -33,7 +33,7 @@ Perun true Perun.htm - 7 + 0 0.8.0.%2a false true