From 8c78abcd1ea57d7eb266e5026f6a84a9d8f4271f Mon Sep 17 00:00:00 2001 From: nikzori Date: Tue, 24 Dec 2024 15:11:41 +0300 Subject: [PATCH] finishing setup for writing values in DGV --- Datasheet.cs | 134 ++++++++++++++++++++++++++++++++++++++++++--------- Main.cs | 19 ++++---- Modbus.cs | 19 +++++--- README.md | 11 +++-- 4 files changed, 138 insertions(+), 45 deletions(-) diff --git a/Datasheet.cs b/Datasheet.cs index 3717a8b..dbae5d6 100644 --- a/Datasheet.cs +++ b/Datasheet.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Net; using System.Runtime.Remoting.Messaging; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; @@ -47,12 +48,15 @@ namespace Gidrolock_Modbus_Scanner DGV_Device.Columns.Add("#", "#"); DGV_Device.Columns[0].FillWeight = 20; + DGV_Device.Columns[0].ReadOnly = true; DGV_Device.Columns.Add("Name", "Имя"); DGV_Device.Columns[1].FillWeight = 40; + DGV_Device.Columns[1].ReadOnly = true; DGV_Device.Columns.Add("Value", "Значение"); DGV_Device.Columns[2].FillWeight = 60; DGV_Device.Columns.Add("Address", "Адрес"); DGV_Device.Columns[3].FillWeight = 30; + DGV_Device.Columns[3].ReadOnly = true; DGV_Device.Columns.Add(new DataGridViewCheckBoxColumn()); DGV_Device.Columns[4].Name = "Опрос"; DGV_Device.Columns[4].FillWeight = 20; @@ -60,6 +64,14 @@ namespace Gidrolock_Modbus_Scanner int rowCount = 0; + DGV_Device.CellEndEdit += (o, e) => + { + if (e.ColumnIndex == 2) + { + + } + }; + foreach (Entry e in entries) { if (e.length > 1) @@ -68,6 +80,8 @@ namespace Gidrolock_Modbus_Scanner if ((e.length == 2 && e.dataType == "uint32") || e.dataType == "string") { DGV_Device.Rows.Add(rowCount, e.name, "", e.address); + if (e.registerType == RegisterType.Input || e.registerType == RegisterType.Discrete) + DGV_Device.Rows[rowCount].Cells[2].ReadOnly = true; rowCount++; } else @@ -77,6 +91,17 @@ namespace Gidrolock_Modbus_Scanner if (i < e.labels.Count) DGV_Device.Rows.Add(rowCount, e.name + ": " + e.labels[i], "", e.address + i); else DGV_Device.Rows.Add(rowCount, e.address + i, "", e.address + i); + + if (i != 0) // Hide rightmost cells for extra registers in the Entry + { + DGV_Device.Rows[rowCount].Cells[4] = new DataGridViewTextBoxCell(); + DGV_Device.Rows[rowCount].Cells[4].Value = ""; + DGV_Device.Rows[rowCount].Cells[4].Style.ForeColor = Color.DarkGray; + DGV_Device.Rows[rowCount].Cells[4].Style.BackColor = Color.DarkGray; + DGV_Device.Rows[rowCount].Cells[4].ReadOnly = true; + } + if (e.registerType == RegisterType.Input || e.registerType == RegisterType.Discrete) + DGV_Device.Rows[rowCount].Cells[2].ReadOnly = true; rowCount++; } } @@ -85,20 +110,35 @@ namespace Gidrolock_Modbus_Scanner else { DGV_Device.Rows.Add(rowCount, e.name, "", e.address); + if (e.registerType == RegisterType.Input || e.registerType == RegisterType.Discrete) + DGV_Device.Rows[rowCount].Cells[2].ReadOnly = true; + if (e.registerType == RegisterType.Coil) + { + DGV_Device.Rows[rowCount].Cells[2] = new DataGridViewComboBoxCell(); + var cbc = DGV_Device.Rows[rowCount].Cells[2] as DataGridViewComboBoxCell; + if (e.valueParse != null) + { + if (e.valueParse.ContainsKey("false")) + cbc.Items.Add(e.valueParse["false"]); + if (e.valueParse.ContainsKey("true")) + cbc.Items.Add(e.valueParse["true"]); + } + else + { + cbc.Items.Add("False"); + cbc.Items.Add("True"); + } + } rowCount++; } } foreach (DataGridViewRow row in DGV_Device.Rows) { row.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; + if (row.Cells[2] is DataGridViewComboBoxCell) + row.Cells[2].Style.Alignment = DataGridViewContentAlignment.MiddleLeft; } - /* - for (int i = 0; i < entries.Count; i++) - { - DGV_Device.Rows.Add(i.ToString(), entries[i].name, "", entries[i].address); - DGV_Device.Rows[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; - } - */ + foreach (DataGridViewColumn column in DGV_Device.Columns) column.SortMode = DataGridViewColumnSortMode.NotSortable; // disabling sorting for now @@ -121,8 +161,9 @@ namespace Gidrolock_Modbus_Scanner DataGridViewCheckBoxCell chbox = DGV_Device.Rows[activeDGVIndex].Cells[4] as DataGridViewCheckBoxCell; if (Convert.ToBoolean(chbox.Value)) { - Console.WriteLine("Polling for " + device.entries[activeEntryIndex].name); - await PollForEntry(entries[activeEntryIndex]).ContinueWith(_ => Task.Delay(150)); + //Console.WriteLine("Polling for " + device.entries[activeEntryIndex].name); + await PollForEntry(entries[activeEntryIndex]); + Thread.Sleep(150); } else //need to skip multiple dgv entries without accidentaly skipping entries { @@ -155,20 +196,22 @@ namespace Gidrolock_Modbus_Scanner public async Task PollForEntry(Entry entry) { byte[] message = new byte[8]; - var send = await Modbus.ReadRegAsync(port, slaveID, (FunctionCode)entry.registerType, entry.address, entry.length); + var send = Modbus.ReadRegAsync(port, slaveID, (FunctionCode)entry.registerType, entry.address, entry.length); isAwaitingResponse = true; - Task delay = Task.WhenAny(Task.Delay(timeout), Task.Run(() => { while (isAwaitingResponse) { } return; })).ContinueWith((t) => + Task delay = Task.WhenAny(Task.Delay(timeout), Task.Run(() => { while (isAwaitingResponse) { } return true; })).ContinueWith((t) => { if (isAwaitingResponse) { Console.WriteLine("Response timed out."); isAwaitingResponse = false; } + return false; }); await delay; + } void PublishResponse(object sender, ModbusResponseEventArgs e) @@ -189,14 +232,43 @@ namespace Gidrolock_Modbus_Scanner if (entries[activeEntryIndex].labels is null || entries[activeEntryIndex].labels.Count == 0) // assume that no labels = 1 entry { if (entries[activeEntryIndex].valueParse is null || entries[activeEntryIndex].valueParse.Keys.Count == 0) - DGV_Device.Rows[activeEntryIndex].Cells[2].Value = e.Data[0] > 0x00 ? "true" : "false"; + { + if (entries[activeEntryIndex].registerType == RegisterType.Coil) + { + DGV_Device.Invoke((MethodInvoker)delegate + { + var cbc = DGV_Device.Rows[activeDGVIndex].Cells[2] as DataGridViewComboBoxCell; + cbc.Value = e.Data[0] > 0x00 ? cbc.Items[1] : cbc.Items[0]; + }); + } + else + { + DGV_Device.Invoke((MethodInvoker)delegate + { + DGV_Device.Rows[activeDGVIndex].Cells[2].Value = e.Data[0] > 0x00 ? "true" : "false"; + }); + } + } else { - try { DGV_Device.Rows[activeEntryIndex].Cells[2].Value = e.Data[0] > 0x00 ? entries[activeEntryIndex].valueParse["true"] : entries[activeEntryIndex].valueParse["false"]; } + try { DGV_Device.Rows[activeDGVIndex].Cells[2].Value = e.Data[0] > 0x00 ? entries[activeEntryIndex].valueParse["true"] : entries[activeEntryIndex].valueParse["false"]; } catch (Exception err) { - MessageBox.Show("Value parsing error for bool entry: " + entries[activeEntryIndex].name + "; " + err.Message); - DGV_Device.Rows[activeEntryIndex].Cells[2].Value = e.Data[0] > 0x00 ? "true" : "false"; + if (entries[activeEntryIndex].registerType == RegisterType.Coil) + { + DGV_Device.Invoke((MethodInvoker)delegate + { + var cbc = DGV_Device.Rows[activeDGVIndex].Cells[2] as DataGridViewComboBoxCell; + cbc.Value = e.Data[0] > 0x00 ? cbc.Items[1] : cbc.Items[0]; + }); + } + else + { + DGV_Device.Invoke((MethodInvoker)delegate + { + DGV_Device.Rows[activeDGVIndex].Cells[2].Value = e.Data[0] > 0x00 ? "true" : "false"; + }); + } } } activeDGVIndex++; @@ -214,7 +286,21 @@ namespace Gidrolock_Modbus_Scanner } for (int i = 0; i < entries[activeEntryIndex].labels.Count; i++) { - DGV_Device.Rows[activeDGVIndex].Cells[2].Value = values[i]; + if (entries[activeEntryIndex].registerType == RegisterType.Coil) + { + DGV_Device.Invoke((MethodInvoker)delegate + { + var cbc = DGV_Device.Rows[activeEntryIndex].Cells[2] as DataGridViewComboBoxCell; + cbc.Value = e.Data[0] > 0x00 ? cbc.Items[1] : cbc.Items[0]; + }); + } + else + { + DGV_Device.Invoke((MethodInvoker)delegate + { + DGV_Device.Rows[activeEntryIndex].Cells[2].Value = e.Data[0] > 0x00 ? "true": "false"; + }); + } activeDGVIndex++; } } @@ -227,7 +313,7 @@ namespace Gidrolock_Modbus_Scanner { //Array.Reverse(e.Data); // this was necessary, but something changed, idk - Console.WriteLine("ushort parsed value: " + value); + //Console.WriteLine("ushort parsed value: " + value); DGV_Device.Rows[activeDGVIndex].Cells[2].Value = value; } else @@ -249,15 +335,19 @@ namespace Gidrolock_Modbus_Scanner try { List values = new List(); - for (int i = 0; i < dbc - 2; i += 2) + for (int i = 0; i < dbc; i += 2) { ushort s = BitConverter.ToUInt16(e.Data, i); - Console.WriteLine("ushort value: " + s); values.Add(s); } + //Console.WriteLine("ushort values count: " + values.Count); + //Console.WriteLine("entity labels count: " + entries[activeEntryIndex].labels.Count); for (int i = 0; i < entries[activeEntryIndex].labels.Count; i++) { - DGV_Device.Rows[activeDGVIndex].Cells[2].Value = values[i]; + DGV_Device.Invoke((MethodInvoker)delegate + { + DGV_Device.Rows[activeDGVIndex].Cells[2].Value = values[i]; + }); activeDGVIndex++; } } @@ -300,9 +390,7 @@ namespace Gidrolock_Modbus_Scanner //MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK); port.DiscardInBuffer(); } - catch (Exception err) { - MessageBox.Show(err.Message, "Publish response error"); - } + catch (Exception err) { MessageBox.Show(err.Message, "Publish response error"); } } if (activeDGVIndex >= DGV_Device.Rows.Count) diff --git a/Main.cs b/Main.cs index 5b7575f..cc2eed2 100644 --- a/Main.cs +++ b/Main.cs @@ -14,7 +14,6 @@ using System.IO; using Newtonsoft.Json; using System.Threading; - namespace Gidrolock_Modbus_Scanner { public partial class App : Form @@ -103,7 +102,7 @@ namespace Gidrolock_Modbus_Scanner CBox_Parity.Items.Add("Нечетн."); CBox_Parity.SelectedIndex = 0; - UpDown_RegLength.Value = 0; + UpDown_RegLength.Value = 1; /* TCP Setup */ /* Radio_SerialPort.Checked = true; @@ -176,11 +175,11 @@ namespace Gidrolock_Modbus_Scanner port.BaudRate = BaudRate[CBox_BaudRate.SelectedIndex]; port.Parity = Parity.None; port.DataBits = DataBits[CBox_DataBits.SelectedIndex]; - port.StopBits = (StopBits)CBox_StopBits.SelectedIndex; + port.StopBits = (StopBits)CBox_StopBits.SelectedIndex; port.ReadTimeout = 3000; port.WriteTimeout = 3000; - + port.ReadBufferSize = 8192; message = new byte[255]; port.Open(); @@ -191,7 +190,7 @@ namespace Gidrolock_Modbus_Scanner { try { - await Modbus.ReadRegAsync(port, (byte)UpDown_ModbusID.Value, functionCode, address, length); + Modbus.ReadRegAsync(port, (byte)UpDown_ModbusID.Value, functionCode, address, length); isAwaitingResponse = true; await Task.Delay(port.ReadTimeout).ContinueWith(_ => { @@ -244,7 +243,7 @@ namespace Gidrolock_Modbus_Scanner port.ReadTimeout = 3000; port.WriteTimeout = 3000; - + port.ReadBufferSize = 8192; message = new byte[255]; port.Open(); @@ -556,7 +555,7 @@ namespace Gidrolock_Modbus_Scanner port.ReadTimeout = 3000; port.WriteTimeout = 3000; - + port.ReadBufferSize = 8192; message = new byte[255]; port.Open(); @@ -584,9 +583,9 @@ namespace Gidrolock_Modbus_Scanner case (FunctionCode.WriteCoil): Console.WriteLine("Trying to force single coil"); if (valueLower == "true" || valueLower == "1") - await Modbus.WriteSingleAsync(port, (FunctionCode)functionCode, (byte)UpDown_ModbusID.Value, (ushort)address, 0xFF_00); + Modbus.WriteSingleAsync(port, (FunctionCode)functionCode, (byte)UpDown_ModbusID.Value, (ushort)address, 0xFF_00); else if (valueLower == "false" || valueLower == "0") - await Modbus.WriteSingleAsync(port, (FunctionCode)functionCode, (byte)UpDown_ModbusID.Value, (ushort)address, 0x00_00); + Modbus.WriteSingleAsync(port, (FunctionCode)functionCode, (byte)UpDown_ModbusID.Value, (ushort)address, 0x00_00); else MessageBox.Show("Неподходящие значения для регистра типа Coil"); break; case (FunctionCode.WriteRegister): @@ -641,7 +640,7 @@ namespace Gidrolock_Modbus_Scanner } if (canWrite) - await Modbus.WriteSingleAsync(port, (FunctionCode)functionCode, (byte)UpDown_ModbusID.Value, (ushort)address, + Modbus.WriteSingleAsync(port, (FunctionCode)functionCode, (byte)UpDown_ModbusID.Value, (ushort)address, (ushort)value); break; default: diff --git a/Modbus.cs b/Modbus.cs index 1c7c7b5..ccaf377 100644 --- a/Modbus.cs +++ b/Modbus.cs @@ -2,6 +2,7 @@ using System.IO.Ports; using System.Runtime.Remoting.Messaging; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static System.Net.Mime.MediaTypeNames; @@ -63,7 +64,7 @@ namespace Gidrolock_Modbus_Scanner #endregion #region Read Functions - public static async Task ReadRegAsync(SerialPort port, byte slaveID, FunctionCode functionCode, ushort address, ushort length) + public static bool ReadRegAsync(SerialPort port, byte slaveID, FunctionCode functionCode, ushort address, ushort length) { //Ensure port is open: if (port.IsOpen) @@ -83,7 +84,7 @@ namespace Gidrolock_Modbus_Scanner //Send modbus message to Serial Port: try { - await Task.Run(() => { port.Write(message, 0, message.Length); }); + port.Write(message, 0, message.Length); return true; } catch (Exception err) @@ -105,7 +106,7 @@ namespace Gidrolock_Modbus_Scanner #endregion #region Write Single Coil/Register - public static async Task WriteSingleAsync(SerialPort port, FunctionCode functionCode, byte slaveID, ushort address, ushort value) + public static bool WriteSingleAsync(SerialPort port, FunctionCode functionCode, byte slaveID, ushort address, ushort value) { //Ensure port is open: if (!port.IsOpen) @@ -239,24 +240,26 @@ namespace Gidrolock_Modbus_Scanner { try { + Thread.Sleep(50); byte[] message = new byte[port.BytesToRead]; + //Console.WriteLine("Bytes to read:" + port.BytesToRead); port.Read(message, 0, port.BytesToRead); - Console.WriteLine("Incoming message: " + ByteArrayToString(message, false)); + //Console.WriteLine("Incoming message: " + ByteArrayToString(message, false)); if (message[1] <= 0x04) // read functions { - Console.WriteLine("It's a read message"); + //Console.WriteLine("It's a read message"); ResponseReceived.Invoke(null, new ModbusResponseEventArgs(message, ModbusStatus.ReadSuccess)); } else { if (message[1] <= 0x10) // write functions { - Console.WriteLine("It's a write message"); + //Console.WriteLine("It's a write message"); ResponseReceived.Invoke(null, new ModbusResponseEventArgs(message, ModbusStatus.WriteSuccess)); } else // error codes { - Console.WriteLine("It's an error"); + //Console.WriteLine("It's an error"); ResponseReceived.Invoke(null, new ModbusResponseEventArgs(message, ModbusStatus.Error)); } } @@ -287,7 +290,7 @@ namespace Gidrolock_Modbus_Scanner { Data[i] = message[i + 3]; } - Console.WriteLine("Read data: " + Modbus.ByteArrayToString(Data, false)); + //Console.WriteLine("Read data: " + Modbus.ByteArrayToString(Data, false)); } else Data = new byte[1] {0x0F}; } diff --git a/README.md b/README.md index f5031c9..b1994a9 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Modbus TCP // "description" : "Smart valve controller unit with wired and wireless leak sensor support", + // Modbus ID , + // , + "modbusID" : 30 + // , // // , @@ -69,8 +73,7 @@ Modbus TCP ### To-Do -1. `bool` -2. . -3. . -4. Modbus TCP +- . + -- +- Modbus TCP