From 330d943b5d2bf93f72c1e63a707e13ae9e34b39f Mon Sep 17 00:00:00 2001 From: nikzori Date: Thu, 12 Dec 2024 15:14:13 +0300 Subject: [PATCH] refactored RTU response event to offload message processing to a single function --- Datasheet.cs | 101 ++++++++--------- Json.cs | 21 +++- Main.Designer.cs | 94 ++++++++++------ Main.cs | 288 ++++++++++++++++++++++++++++------------------- Modbus.cs | 92 ++++++++++++--- 5 files changed, 372 insertions(+), 224 deletions(-) diff --git a/Datasheet.cs b/Datasheet.cs index 36ad5ea..846e4b3 100644 --- a/Datasheet.cs +++ b/Datasheet.cs @@ -25,12 +25,12 @@ namespace Gidrolock_Modbus_Scanner Device device = App.device; List entries; int activeEntryIndex; // entry index for modbus responses - SerialPort port = App.port; + SerialPort port = Modbus.port; bool closed = false; public Datasheet(byte slaveID) { - App.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PublishResponse); + Modbus.ResponseReceived += PublishResponse; this.slaveID = slaveID; entries = device.entries; @@ -91,7 +91,7 @@ namespace Gidrolock_Modbus_Scanner Console.WriteLine("Sending message: " + Modbus.ByteArrayToString(Modbus.BuildMessage(slaveID, (byte)entry.registerType, entry.address, entry.length, ref message))); var send = await Modbus.ReadRegAsync(port, slaveID, (FunctionCode)entry.registerType, entry.address, entry.length); isAwaitingResponse = true; - + Task delay = Task.Delay(timeout).ContinueWith((t) => { if (isAwaitingResponse) @@ -105,68 +105,55 @@ namespace Gidrolock_Modbus_Scanner await delay; } - void PublishResponse(object sender, EventArgs e) + void PublishResponse(object sender, ModbusResponseEventArgs e) { - Console.WriteLine("Received data on port."); if (isAwaitingResponse) { isAwaitingResponse = false; - if (!isProcessingResponse) - { - isProcessingResponse = true; - try + try + { + + byte length = e.message[2]; + Console.WriteLine("Data length is:" + length); + byte[] data = new byte[length]; + for (int i = 0; i < length; i++) + data[i] = e.message[i + 3]; + + Console.WriteLine("Data after processing in Datasheet.cs: " + Modbus.ByteArrayToString(data)); + + switch (entries[activeEntryIndex].dataType) { - message = new byte[255]; - port.Read(message, 0, 3); - int length = (int)message[2]; - for (int i = 0; i < length + 2; i++) - { - port.Read(message, i + 3, 1); - } - byte[] data = new byte[length]; - for (int i = 0; i < length; i++) - { - data[i] = message[i+3]; - } - Console.WriteLine("Received message: " + Modbus.ByteArrayToString(message)); - Console.WriteLine("Data trimmed: " + Modbus.ByteArrayToString(data)); - string dataCleaned = Modbus.ByteArrayToString(message); - - switch (entries[activeEntryIndex].dataType) - { - case ("bool"): - DGV_Device.Rows[activeEntryIndex].Cells[2].Value = data[0] > 0x00 ? "true" : "false"; - break; - case ("uint16"): - Array.Reverse(data); // BitConverter.ToUInt is is little endian, I guess, so we need to flip the array - ushort test = BitConverter.ToUInt16(data, 0); - Console.WriteLine("ushort parsed value: " + test); - DGV_Device.Rows[activeEntryIndex].Cells[2].Value = test; - break; - case ("uint32"): - Array.Reverse(data); - DGV_Device.Rows[activeEntryIndex].Cells[2].Value = BitConverter.ToUInt32(data, 0); - break; - case ("utf8"): - DGV_Device.Rows[activeEntryIndex].Cells[2].Value = System.Text.Encoding.UTF8.GetString(data); - break; - default: - MessageBox.Show("Wrong data type set for entry " + entries[activeEntryIndex].name); - break; - } - - - //MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK); - port.DiscardInBuffer(); - isProcessingResponse = false; - } - catch (Exception err) - { - MessageBox.Show(err.Message, "Event Error"); - isProcessingResponse = false; + case ("bool"): + DGV_Device.Rows[activeEntryIndex].Cells[2].Value = data[0] > 0x00 ? "true" : "false"; + break; + case ("uint16"): + Array.Reverse(data); // BitConverter.ToUInt is is little endian, I guess, so we need to flip the array + ushort test = BitConverter.ToUInt16(data, 0); + Console.WriteLine("ushort parsed value: " + test); + DGV_Device.Rows[activeEntryIndex].Cells[2].Value = test; + break; + case ("uint32"): + Array.Reverse(data); + DGV_Device.Rows[activeEntryIndex].Cells[2].Value = BitConverter.ToUInt32(data, 0); + break; + case ("utf8"): + DGV_Device.Rows[activeEntryIndex].Cells[2].Value = System.Text.Encoding.UTF8.GetString(data); + break; + default: + MessageBox.Show("Wrong data type set for entry " + entries[activeEntryIndex].name); + break; } + + + //MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK); + port.DiscardInBuffer(); } + catch (Exception err) + { + //MessageBox.Show(err.Message, "Event Error"); + } + } } } diff --git a/Json.cs b/Json.cs index 4a6277e..4dd8378 100644 --- a/Json.cs +++ b/Json.cs @@ -13,11 +13,12 @@ namespace Gidrolock_Modbus_Scanner public string name; public string description; public List entries; - - public Device(string name, string description, List entries) + public CheckEntry checkEntry; + public Device(string name, string description, CheckEntry checkEntry, List entries) { this.name = name; this.description = description; + this.checkEntry = checkEntry; this.entries = entries; } } @@ -40,5 +41,21 @@ namespace Gidrolock_Modbus_Scanner this.readOnce = readOnce; } } + public struct CheckEntry + { + public RegisterType registerType; + public ushort address; + public ushort length; + public string dataType; + public string expectedValue; + public CheckEntry(RegisterType registerType, ushort address, ushort length, string dataType, string expectedValue) + { + this.registerType = registerType; + this.address = address; + this.length = length; + this.dataType = dataType; + this.expectedValue = expectedValue; + } + } public enum RegisterType { Coil = 1, Discrete = 2, Holding = 3, Input = 4} } diff --git a/Main.Designer.cs b/Main.Designer.cs index 7b6e89e..3621800 100644 --- a/Main.Designer.cs +++ b/Main.Designer.cs @@ -80,9 +80,11 @@ this.groupBox4 = new System.Windows.Forms.GroupBox(); this.Radio_Ethernet = new System.Windows.Forms.RadioButton(); this.Radio_SerialPort = new System.Windows.Forms.RadioButton(); + this.Label_ConfigTip = new System.Windows.Forms.Label(); this.Button_LoadConfig = new System.Windows.Forms.Button(); - this.label12 = new System.Windows.Forms.Label(); - this.Label_Config = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.Label_ConfPath = new System.Windows.Forms.Label(); + this.button1 = new System.Windows.Forms.Button(); this.GBox_Serial.SuspendLayout(); this.panel11.SuspendLayout(); this.panel10.SuspendLayout(); @@ -105,6 +107,7 @@ this.panel17.SuspendLayout(); this.panel18.SuspendLayout(); this.groupBox4.SuspendLayout(); + this.groupBox1.SuspendLayout(); this.SuspendLayout(); // // GBox_Serial @@ -115,7 +118,7 @@ this.GBox_Serial.Controls.Add(this.panel7); this.GBox_Serial.Controls.Add(this.panel2); this.GBox_Serial.Controls.Add(this.panel1); - this.GBox_Serial.Location = new System.Drawing.Point(12, 12); + this.GBox_Serial.Location = new System.Drawing.Point(12, 92); this.GBox_Serial.Name = "GBox_Serial"; this.GBox_Serial.Size = new System.Drawing.Size(490, 65); this.GBox_Serial.TabIndex = 0; @@ -315,7 +318,7 @@ // this.Button_Connect.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.Button_Connect.Location = new System.Drawing.Point(402, 155); + this.Button_Connect.Location = new System.Drawing.Point(402, 235); this.Button_Connect.Name = "Button_Connect"; this.Button_Connect.Size = new System.Drawing.Size(100, 25); this.Button_Connect.TabIndex = 4; @@ -325,7 +328,7 @@ // // TextBox_Log // - this.TextBox_Log.Location = new System.Drawing.Point(12, 192); + this.TextBox_Log.Location = new System.Drawing.Point(12, 269); this.TextBox_Log.Multiline = true; this.TextBox_Log.Name = "TextBox_Log"; this.TextBox_Log.ReadOnly = true; @@ -340,7 +343,7 @@ this.groupBox2.Controls.Add(this.Button_SendCommand); this.groupBox2.Controls.Add(this.panel3); this.groupBox2.Controls.Add(this.panel4); - this.groupBox2.Location = new System.Drawing.Point(12, 316); + this.groupBox2.Location = new System.Drawing.Point(12, 393); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(490, 63); this.groupBox2.TabIndex = 5; @@ -465,7 +468,7 @@ this.GBox_Ethernet.Controls.Add(this.panel16); this.GBox_Ethernet.Controls.Add(this.panel17); this.GBox_Ethernet.Controls.Add(this.panel18); - this.GBox_Ethernet.Location = new System.Drawing.Point(12, 82); + this.GBox_Ethernet.Location = new System.Drawing.Point(12, 162); this.GBox_Ethernet.Name = "GBox_Ethernet"; this.GBox_Ethernet.Size = new System.Drawing.Size(334, 65); this.GBox_Ethernet.TabIndex = 6; @@ -551,7 +554,7 @@ // this.groupBox4.Controls.Add(this.Radio_Ethernet); this.groupBox4.Controls.Add(this.Radio_SerialPort); - this.groupBox4.Location = new System.Drawing.Point(348, 82); + this.groupBox4.Location = new System.Drawing.Point(348, 162); this.groupBox4.Name = "groupBox4"; this.groupBox4.Size = new System.Drawing.Size(154, 65); this.groupBox4.TabIndex = 7; @@ -582,44 +585,67 @@ this.Radio_SerialPort.UseVisualStyleBackColor = true; this.Radio_SerialPort.CheckedChanged += new System.EventHandler(this.Radio_SerialPort_CheckedChanged); // + // Label_ConfigTip + // + this.Label_ConfigTip.AutoSize = true; + this.Label_ConfigTip.Location = new System.Drawing.Point(8, 16); + this.Label_ConfigTip.Name = "Label_ConfigTip"; + this.Label_ConfigTip.Size = new System.Drawing.Size(94, 13); + this.Label_ConfigTip.TabIndex = 10; + this.Label_ConfigTip.Text = "Выбранный путь:"; + // // Button_LoadConfig // this.Button_LoadConfig.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.Button_LoadConfig.Location = new System.Drawing.Point(292, 155); + this.Button_LoadConfig.Location = new System.Drawing.Point(415, 43); this.Button_LoadConfig.Name = "Button_LoadConfig"; - this.Button_LoadConfig.Size = new System.Drawing.Size(100, 25); - this.Button_LoadConfig.TabIndex = 8; - this.Button_LoadConfig.Text = "Выбрать"; + this.Button_LoadConfig.Size = new System.Drawing.Size(69, 25); + this.Button_LoadConfig.TabIndex = 11; + this.Button_LoadConfig.Text = "Файл"; this.Button_LoadConfig.UseVisualStyleBackColor = true; this.Button_LoadConfig.Click += new System.EventHandler(this.LoadConfig); // - // label12 + // groupBox1 // - this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(9, 161); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(83, 13); - this.label12.TabIndex = 9; - this.label12.Text = "Конфигурация:"; + this.groupBox1.Controls.Add(this.Label_ConfPath); + this.groupBox1.Controls.Add(this.button1); + this.groupBox1.Controls.Add(this.Button_LoadConfig); + this.groupBox1.Controls.Add(this.Label_ConfigTip); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(490, 74); + this.groupBox1.TabIndex = 13; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Конфигурация"; // - // Label_Config + // Label_ConfPath // - this.Label_Config.AutoSize = true; - this.Label_Config.Location = new System.Drawing.Point(90, 161); - this.Label_Config.Name = "Label_Config"; - this.Label_Config.Size = new System.Drawing.Size(66, 13); - this.Label_Config.TabIndex = 1; - this.Label_Config.Text = "не выбрана"; + this.Label_ConfPath.Location = new System.Drawing.Point(9, 29); + this.Label_ConfPath.Name = "Label_ConfPath"; + this.Label_ConfPath.Size = new System.Drawing.Size(400, 39); + this.Label_ConfPath.TabIndex = 14; + this.Label_ConfPath.Text = "Файл не выбран."; + this.Label_ConfPath.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // button1 + // + this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.button1.Location = new System.Drawing.Point(415, 12); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(69, 25); + this.button1.TabIndex = 13; + this.button1.Text = "Папка"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.LoadFolder); // // App // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(514, 391); - this.Controls.Add(this.Label_Config); - this.Controls.Add(this.label12); - this.Controls.Add(this.Button_LoadConfig); + this.ClientSize = new System.Drawing.Size(514, 467); + this.Controls.Add(this.groupBox1); this.Controls.Add(this.groupBox4); this.Controls.Add(this.GBox_Ethernet); this.Controls.Add(this.groupBox2); @@ -669,6 +695,8 @@ this.panel18.PerformLayout(); this.groupBox4.ResumeLayout(false); this.groupBox4.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -727,9 +755,11 @@ private System.Windows.Forms.GroupBox groupBox4; private System.Windows.Forms.RadioButton Radio_Ethernet; private System.Windows.Forms.RadioButton Radio_SerialPort; + private System.Windows.Forms.Label Label_ConfigTip; private System.Windows.Forms.Button Button_LoadConfig; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.Label Label_Config; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label Label_ConfPath; } } diff --git a/Main.cs b/Main.cs index 2c79a23..88cff07 100644 --- a/Main.cs +++ b/Main.cs @@ -8,42 +8,52 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; -using System.Drawing.Drawing2D; -using System.Threading; -using System.Runtime; -using System.Web; -using System.Windows.Forms.Automation; -using System.Diagnostics; using System.Text.RegularExpressions; using System.Net.Sockets; using System.IO; using Newtonsoft.Json; + namespace Gidrolock_Modbus_Scanner { public partial class App : Form { - public static int[] BaudRate = new int[] - { - 110, 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 76800, 115200, 230300, 460800, 921600 + public static int[] BaudRate = new int[] + { + 110, 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 76800, 115200, 230300, 460800, 921600 }; public static int[] DataBits = new int[] { 7, 8 }; Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); byte[] message = new byte[255]; public bool isAwaitingResponse = false; - public bool isProcessingResponse = false; public short[] res = new short[12]; - public static SerialPort port = new SerialPort(); + SerialPort port = Modbus.port; public int expectedLength = 0; Datasheet datasheet; + public SelectedPath selectedPath = SelectedPath.Folder; - public static Device device; + public static Device device; // Deserialized .json object + string path = String.Empty; // Path to selected file/folder + string defaultPath = Application.StartupPath + "\\Configs"; // Default folder path + OpenFileDialog ofd = new OpenFileDialog(); + FolderBrowserDialog fbd = new FolderBrowserDialog(); + + Dictionary> juju = new Dictionary>(); // dictionary for device identification + string[] configs; + + public byte[] latestMessage; #region Initialization public App() { InitializeComponent(); - port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PortDataReceived); + Modbus.Init(); + Modbus.ResponseReceived += OnResponseReceived; + ofd.InitialDirectory = Application.StartupPath; + ofd.Filter = "JSON files (*.json)|*.json"; + ofd.FilterIndex = 2; + ofd.RestoreDirectory = true; + this.UpDown_ModbusID.Value = 30; TextBox_Log.Text = "Приложение готово к работе."; @@ -102,6 +112,22 @@ namespace Gidrolock_Modbus_Scanner TBox_IP.Text = "192.168.3.7"; TBox_Port.Text = "8887"; TBox_Timeout.Text = "3"; + if (Directory.GetDirectories(Application.StartupPath).Contains(Application.StartupPath + "\\Configs") == false) + { + Task.Delay(1500).ContinueWith(t => + { + MessageBox.Show("Приложение не нашло стандартную папку для конфигураций. Была создана папка 'Configs' в папке с приложением."); + Directory.CreateDirectory(Application.StartupPath + "\\Configs"); + Console.WriteLine("New initial directory for OpenFile: " + ofd.InitialDirectory); + }); + } + ofd.InitialDirectory = Application.StartupPath + "\\Configs"; + path = defaultPath; + UpdatePathLabel(); + } + void UpdatePathLabel() + { + Label_ConfPath.Text = path; } void App_FormClosed(object sender, FormClosedEventArgs e) { @@ -205,44 +231,127 @@ namespace Gidrolock_Modbus_Scanner private async void ButtonConnect_Click(object sender, EventArgs e) { - if (device is null) - MessageBox.Show("Выберите конфигурацию для подключения и опроса устройства."); - else + if (path == String.Empty) { - /* - Port Setup - */ - if (port.IsOpen) - port.Close(); + MessageBox.Show("Выберите конфигурацию для подключения и опроса устройства."); + return; + } + if (CBox_Ports.SelectedItem.ToString() == "COM1") + { + DialogResult res = MessageBox.Show("Выбран серийный порт COM1, который обычно является портом PS/2 или RS-232, не подключенным к Modbus устройству. Продолжить?", "Внимание", MessageBoxButtons.OKCancel); + if (res == DialogResult.Cancel) + return; + } - port.Handshake = Handshake.None; - port.PortName = CBox_Ports.Text; - port.BaudRate = BaudRate[CBox_BaudRate.SelectedIndex]; - port.Parity = Parity.None; - port.DataBits = DataBits[CBox_DataBits.SelectedIndex]; - port.StopBits = (StopBits)CBox_StopBits.SelectedIndex; + /* - Port Setup - */ + if (port.IsOpen) + port.Close(); - port.ReadTimeout = 3000; - port.WriteTimeout = 3000; + port.Handshake = Handshake.None; + port.PortName = CBox_Ports.Text; + port.BaudRate = BaudRate[CBox_BaudRate.SelectedIndex]; + port.Parity = Parity.None; + port.DataBits = DataBits[CBox_DataBits.SelectedIndex]; + port.StopBits = (StopBits)CBox_StopBits.SelectedIndex; + + port.ReadTimeout = 3000; + port.WriteTimeout = 3000; - message = new byte[255]; - port.Open(); + message = new byte[255]; + port.Open(); + + /* - Checking - */ + if (selectedPath == SelectedPath.File) + { + var fileContent = string.Empty; + var filePath = string.Empty; + //Read the contents of the file into a stream + var fileStream = ofd.OpenFile(); + + using (StreamReader reader = new StreamReader(fileStream)) + { + fileContent = reader.ReadToEnd(); + } - AddLog("Попытка подключиться к устройству " + device.name); try { - datasheet = new Datasheet((byte)UpDown_ModbusID.Value); - datasheet.Show(); + device = JsonConvert.DeserializeObject(fileContent); + Label_ConfigTip.Text = device.name; } catch (Exception err) { MessageBox.Show(err.Message); } - /* - if (Radio_SerialPort.Checked) - await SendMessageAsync(FunctionCode.InputRegister, 200, 6); - //else EthernetParse(); - */ } + else + { + string[] _configs = Directory.GetFiles(path, "*.json"); + if (configs != _configs) + { + // something changed in the config folder, or we haven't gone through configs, + // remake the dictionary + configs = _configs; + juju = new Dictionary>(); + + var fileContent = string.Empty; + FileStream fileStream; + Device _device; + + foreach (string path in configs) + { + fileStream = File.OpenRead(path); + using (StreamReader reader = new StreamReader(fileStream)) + fileContent = reader.ReadToEnd(); + // get device object from .json + _device = JsonConvert.DeserializeObject(fileContent); + + // compare device object to key of each dictionary; + // add to that dictionary if device's check entry registers match the key + foreach (CheckEntry ce in juju.Keys) + { + if (_device.checkEntry.address == ce.address && _device.checkEntry.length == ce.length && _device.checkEntry.dataType == ce.dataType) + { + juju[ce].Add(_device); + break; + } + } + } + + + } + // all configs are sorted out, we can poll for each checkEntry + + foreach (CheckEntry ce in juju.Keys) + { + byte[] response; + // send read request to device, + // check for error codes or timeouts + // if we get normal response, go through + } + + // with dictionaries arranged, go through every key, discarding those that return error + // if device returns a coherent reply, go through expected values associated with the key + } + + + + AddLog("Попытка подключиться к устройству " + device.name); + try + { + datasheet = new Datasheet((byte)UpDown_ModbusID.Value); + datasheet.Show(); + } + catch (Exception err) + { + MessageBox.Show(err.Message); + } + /* + if (Radio_SerialPort.Checked) + await SendMessageAsync(FunctionCode.InputRegister, 200, 6); + //else EthernetParse(); + */ + } async void EthernetParse() @@ -267,9 +376,8 @@ namespace Gidrolock_Modbus_Scanner // set up an event listener to receive the response await SocketDataTransfer(data); - } - + } void CBox_Ports_Click(object sender, EventArgs e) @@ -278,50 +386,11 @@ namespace Gidrolock_Modbus_Scanner CBox_Ports.Items.AddRange(SerialPort.GetPortNames()); } - void PortDataReceived(object sender, EventArgs e) + void OnResponseReceived(object sender, ModbusResponseEventArgs e) { - if (datasheet is null) - return; - if (datasheet.Enabled) - return; - - Console.WriteLine("Data receieved on Serial Port"); isAwaitingResponse = false; - - if (!isProcessingResponse) - { - isProcessingResponse = true; - try - { - port.Read(message, 0, 3); - int length = (int)message[2]; - for (int i = 0; i < length + 2; i++) - { - port.Read(message, i + 3, 1); - } - byte[] data = new byte[length]; - for (int i = 0; i < length; i++) - { - data[i] = message[i + 3]; - } - - string dataCleaned = Modbus.ByteArrayToString(message); - TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + dataCleaned); }); - TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("ASCII: " + "wip"); }); - - port.DiscardInBuffer(); - isProcessingResponse = false; - } - catch (Exception err) - { - MessageBox.Show(err.Message); - isProcessingResponse = false; - } - } - else Console.WriteLine("Already processing incoming message!"); - - //port.Close(); - + TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + Modbus.ByteArrayToString(e.message)); }); + TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("UTF8: " + Encoding.UTF8.GetString(e.message)); }); } void AddLog(string message) @@ -384,49 +453,38 @@ namespace Gidrolock_Modbus_Scanner Console.Out.WriteLine("Received data on TCP socket: " + resParsed); AddLog("Response from TCP Server: " + resParsed); - } + } }); return true; } private void LoadConfig(object sender, EventArgs e) { - var fileContent = string.Empty; - var filePath = string.Empty; - - using (OpenFileDialog openFileDialog = new OpenFileDialog()) + if (ofd.ShowDialog() == DialogResult.OK) { - openFileDialog.InitialDirectory = Application.StartupPath; - openFileDialog.Filter = "JSON files (*.json)|*.json"; - openFileDialog.FilterIndex = 2; - openFileDialog.RestoreDirectory = true; + //Get the path of specified file + path = ofd.FileName; + Label_ConfPath.Text = ofd.FileName; - if (openFileDialog.ShowDialog() == DialogResult.OK) - { - //Get the path of specified file - filePath = openFileDialog.FileName; - - //Read the contents of the file into a stream - var fileStream = openFileDialog.OpenFile(); - - using (StreamReader reader = new StreamReader(fileStream)) - { - fileContent = reader.ReadToEnd(); - } - - try - { - device = JsonConvert.DeserializeObject(fileContent); - Label_Config.Text = device.name; - } - catch (Exception err) - { - MessageBox.Show(err.Message); - } - } + selectedPath = SelectedPath.File; } + UpdatePathLabel(); + } + + private void LoadFolder(object sender, EventArgs e) + { + + fbd.RootFolder = Environment.SpecialFolder.MyComputer; + if (fbd.ShowDialog() == DialogResult.OK) + { + path = fbd.SelectedPath; + Label_ConfPath.Text = fbd.SelectedPath; + selectedPath = SelectedPath.Folder; + } + UpdatePathLabel(); } } -} +} -public enum FunctionCode { ReadCoil = 1, ReadDiscrete = 2, ReadHolding = 3, ReadInput = 4, WriteCoil = 5, WriteRegister = 6, WriteMultCoils = 15, WriteMultRegisters = 16}; +public enum FunctionCode { ReadCoil = 1, ReadDiscrete = 2, ReadHolding = 3, ReadInput = 4, WriteCoil = 5, WriteRegister = 6, WriteMultCoils = 15, WriteMultRegisters = 16 }; +public enum SelectedPath { File, Folder }; diff --git a/Modbus.cs b/Modbus.cs index d56a944..e970dc5 100644 --- a/Modbus.cs +++ b/Modbus.cs @@ -1,17 +1,23 @@ using System; using System.IO.Ports; -using System.Runtime; -using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using System.Threading; namespace Gidrolock_Modbus_Scanner { public static class Modbus { + public static SerialPort port = new SerialPort(); + + + public static event EventHandler ResponseReceived = delegate { }; + + public static void Init() + { + port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PortDataReceived); + } + #region Build Message public static byte[] BuildMessage(byte modbusID, byte functionCode, ushort address, ushort length, ref byte[] message) { @@ -116,20 +122,7 @@ namespace Gidrolock_Modbus_Scanner public static string ByteArrayToString(byte[] bytes) { - int length = bytes.Length - 1; - // snip off the empty bytes at the end - for (int i = length; i >= 0; i--) - { - if (bytes[i] != 0) - { - length = i + 1; - break; - } - } - - byte[] res = new byte[length]; - for (int i = 0; i < length; i++) - res[i] = bytes[i]; + byte[] res = CleanByteArray(bytes); string dataString = BitConverter.ToString(res); string result = ""; @@ -142,6 +135,25 @@ namespace Gidrolock_Modbus_Scanner return result; } + public static byte[] CleanByteArray(byte[] bytes) + { + int length = bytes.Length - 1; + // snip off the empty bytes at the end + for (int i = length; i >= 0; i--) + { + if (bytes[i] != 0) + { + length = i + 1; + break; + } + } + + byte[] res = new byte[length]; + for (int i = 0; i < length; i++) { res[i] = bytes[i]; } + + return res; + } + #region CRC Computation static void GetCRC(byte[] message, ref byte[] CRC) @@ -170,5 +182,49 @@ namespace Gidrolock_Modbus_Scanner CRC[0] = CRCLow = (byte)(CRCFull & 0xFF); } #endregion + + static void PortDataReceived(object sender, EventArgs e) + { + Console.WriteLine("Data receieved on Serial Port"); + + try + { + byte[] message = new byte[port.BytesToRead]; + port.Read(message, 0, 3); + int length = (int)message[2]; + for (int i = 0; i < length + 2; i++) + { + port.Read(message, i + 3, 1); + } + Console.WriteLine("Raw data from port: " + BitConverter.ToString(message)); + byte[] data = new byte[length]; + for (int i = 0; i < length; i++) + { + data[i] = message[i + 3]; + } + string dataCleaned = ByteArrayToString(message); + Console.WriteLine("Received response: " + dataCleaned); + Console.WriteLine("UTF8: " + Encoding.UTF8.GetString(data)); + + port.DiscardInBuffer(); + + ResponseReceived.Invoke(null, new ModbusResponseEventArgs(message)); + } + catch (Exception err) + { + MessageBox.Show(err.Message); + } + } + } + + public class ModbusResponseEventArgs : EventArgs + { + public byte[] message { get; set; } + public ModbusResponseEventArgs(byte[] message) + { + this.message = message; + } + } + } \ No newline at end of file