added manual read requests

This commit is contained in:
nikzori
2024-11-05 16:57:05 +03:00
parent 30bd39350b
commit d2c4dc3ec3
4 changed files with 258 additions and 85 deletions

167
Form1.Designer.cs generated
View File

@@ -37,11 +37,28 @@
this.panel1 = new System.Windows.Forms.Panel(); this.panel1 = new System.Windows.Forms.Panel();
this.CBox_Ports = new System.Windows.Forms.ComboBox(); this.CBox_Ports = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.Label_Status = new System.Windows.Forms.Label(); this.TextBox_Log = new System.Windows.Forms.TextBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.panel5 = new System.Windows.Forms.Panel();
this.UpDown_RegLength = new System.Windows.Forms.NumericUpDown();
this.label5 = new System.Windows.Forms.Label();
this.Button_SendCommand = new System.Windows.Forms.Button();
this.panel3 = new System.Windows.Forms.Panel();
this.UpDown_RegAddress = new System.Windows.Forms.NumericUpDown();
this.label3 = new System.Windows.Forms.Label();
this.panel4 = new System.Windows.Forms.Panel();
this.CBox_Function = new System.Windows.Forms.ComboBox();
this.label4 = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout(); this.groupBox1.SuspendLayout();
this.panel2.SuspendLayout(); this.panel2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.UpDown_ModbusID)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.UpDown_ModbusID)).BeginInit();
this.panel1.SuspendLayout(); this.panel1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.panel5.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.UpDown_RegLength)).BeginInit();
this.panel3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.UpDown_RegAddress)).BeginInit();
this.panel4.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// groupBox1 // groupBox1
@@ -51,7 +68,7 @@
this.groupBox1.Controls.Add(this.panel1); this.groupBox1.Controls.Add(this.panel1);
this.groupBox1.Location = new System.Drawing.Point(12, 12); this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1"; this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(310, 63); this.groupBox1.Size = new System.Drawing.Size(344, 63);
this.groupBox1.TabIndex = 0; this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false; this.groupBox1.TabStop = false;
this.groupBox1.Text = "Подключение"; this.groupBox1.Text = "Подключение";
@@ -60,7 +77,7 @@
// //
this.ButtonConnect.Location = new System.Drawing.Point(162, 34); this.ButtonConnect.Location = new System.Drawing.Point(162, 34);
this.ButtonConnect.Name = "ButtonConnect"; this.ButtonConnect.Name = "ButtonConnect";
this.ButtonConnect.Size = new System.Drawing.Size(146, 23); this.ButtonConnect.Size = new System.Drawing.Size(176, 23);
this.ButtonConnect.TabIndex = 4; this.ButtonConnect.TabIndex = 4;
this.ButtonConnect.Text = "Подключиться"; this.ButtonConnect.Text = "Подключиться";
this.ButtonConnect.UseVisualStyleBackColor = true; this.ButtonConnect.UseVisualStyleBackColor = true;
@@ -119,23 +136,126 @@
this.label1.TabIndex = 0; this.label1.TabIndex = 0;
this.label1.Text = "Порт"; this.label1.Text = "Порт";
// //
// Label_Status // TextBox_Log
// //
this.Label_Status.Location = new System.Drawing.Point(15, 87); this.TextBox_Log.Location = new System.Drawing.Point(12, 82);
this.Label_Status.Name = "Label_Status"; this.TextBox_Log.Multiline = true;
this.Label_Status.Size = new System.Drawing.Size(307, 40); this.TextBox_Log.Name = "TextBox_Log";
this.Label_Status.TabIndex = 5; this.TextBox_Log.ReadOnly = true;
this.Label_Status.Text = "Статус: истекло время ожидания ответа. Проверьте указаный порт, Modbus ID и стату" + this.TextBox_Log.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
"с устройства."; this.TextBox_Log.Size = new System.Drawing.Size(417, 87);
this.TextBox_Log.TabIndex = 1;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.panel5);
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, 175);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(417, 63);
this.groupBox2.TabIndex = 5;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Команды";
//
// panel5
//
this.panel5.Controls.Add(this.UpDown_RegLength);
this.panel5.Controls.Add(this.label5);
this.panel5.Location = new System.Drawing.Point(259, 20);
this.panel5.Name = "panel5";
this.panel5.Size = new System.Drawing.Size(75, 43);
this.panel5.TabIndex = 3;
//
// UpDown_RegLength
//
this.UpDown_RegLength.Location = new System.Drawing.Point(6, 17);
this.UpDown_RegLength.Name = "UpDown_RegLength";
this.UpDown_RegLength.Size = new System.Drawing.Size(66, 20);
this.UpDown_RegLength.TabIndex = 1;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(3, 0);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(40, 13);
this.label5.TabIndex = 0;
this.label5.Text = "Длина";
//
// Button_SendCommand
//
this.Button_SendCommand.Location = new System.Drawing.Point(337, 35);
this.Button_SendCommand.Name = "Button_SendCommand";
this.Button_SendCommand.Size = new System.Drawing.Size(71, 23);
this.Button_SendCommand.TabIndex = 4;
this.Button_SendCommand.Text = "Отправить";
this.Button_SendCommand.UseVisualStyleBackColor = true;
this.Button_SendCommand.Click += new System.EventHandler(this.Button_SendCommand_Click);
//
// panel3
//
this.panel3.Controls.Add(this.UpDown_RegAddress);
this.panel3.Controls.Add(this.label3);
this.panel3.Location = new System.Drawing.Point(162, 20);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(91, 43);
this.panel3.TabIndex = 2;
//
// UpDown_RegAddress
//
this.UpDown_RegAddress.Location = new System.Drawing.Point(6, 17);
this.UpDown_RegAddress.Name = "UpDown_RegAddress";
this.UpDown_RegAddress.Size = new System.Drawing.Size(82, 20);
this.UpDown_RegAddress.TabIndex = 1;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(3, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(38, 13);
this.label3.TabIndex = 0;
this.label3.Text = "Адрес";
//
// panel4
//
this.panel4.Controls.Add(this.CBox_Function);
this.panel4.Controls.Add(this.label4);
this.panel4.Location = new System.Drawing.Point(0, 20);
this.panel4.Name = "panel4";
this.panel4.Size = new System.Drawing.Size(156, 43);
this.panel4.TabIndex = 0;
//
// CBox_Function
//
this.CBox_Function.FormattingEnabled = true;
this.CBox_Function.Location = new System.Drawing.Point(6, 17);
this.CBox_Function.Name = "CBox_Function";
this.CBox_Function.Size = new System.Drawing.Size(147, 21);
this.CBox_Function.TabIndex = 1;
this.CBox_Function.Text = "01 - Read Coil";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(3, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(53, 13);
this.label4.TabIndex = 0;
this.label4.Text = "Функция";
// //
// App // App
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(333, 84); this.ClientSize = new System.Drawing.Size(432, 242);
this.Controls.Add(this.Label_Status); this.Controls.Add(this.groupBox2);
this.Controls.Add(this.TextBox_Log);
this.Controls.Add(this.groupBox1); this.Controls.Add(this.groupBox1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "App"; this.Name = "App";
this.Text = "Gidrolock Modbus Scanner"; this.Text = "Gidrolock Modbus Scanner";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.App_FormClosed); this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.App_FormClosed);
@@ -146,7 +266,17 @@
((System.ComponentModel.ISupportInitialize)(this.UpDown_ModbusID)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.UpDown_ModbusID)).EndInit();
this.panel1.ResumeLayout(false); this.panel1.ResumeLayout(false);
this.panel1.PerformLayout(); this.panel1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.panel5.ResumeLayout(false);
this.panel5.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.UpDown_RegLength)).EndInit();
this.panel3.ResumeLayout(false);
this.panel3.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.UpDown_RegAddress)).EndInit();
this.panel4.ResumeLayout(false);
this.panel4.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
@@ -160,7 +290,18 @@
private System.Windows.Forms.ComboBox CBox_Ports; private System.Windows.Forms.ComboBox CBox_Ports;
private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button ButtonConnect; private System.Windows.Forms.Button ButtonConnect;
private System.Windows.Forms.Label Label_Status; private System.Windows.Forms.TextBox TextBox_Log;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Panel panel5;
private System.Windows.Forms.NumericUpDown UpDown_RegLength;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Button Button_SendCommand;
private System.Windows.Forms.Panel panel3;
private System.Windows.Forms.NumericUpDown UpDown_RegAddress;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Panel panel4;
private System.Windows.Forms.ComboBox CBox_Function;
private System.Windows.Forms.Label label4;
} }
} }

View File

@@ -17,15 +17,28 @@ namespace Gidrolock_Modbus_Scanner
{ {
public partial class App : Form public partial class App : Form
{ {
int offset = 0;
byte[] data = new byte[255];
public bool isAwaitingResponse = false; public bool isAwaitingResponse = false;
public short[] res = new short[12]; public short[] res = new short[12];
public SerialPort port = new SerialPort(); public SerialPort port = new SerialPort();
public int expectedLength = 0;
public App() public App()
{ {
InitializeComponent(); InitializeComponent();
this.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PortDataReceived); this.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(PortDataReceived);
this.UpDown_ModbusID.Value = 30; this.UpDown_ModbusID.Value = 30;
TextBox_Log.Text = "Приложение готово к работе.";
CBox_Function.Items.Add("01 - Read Coil");
CBox_Function.Items.Add("02 - Read Discrete Input");
CBox_Function.Items.Add("03 - Read Holding Register");
CBox_Function.Items.Add("04 - Read Input Register");
CBox_Function.SelectedItem = CBox_Function.Items[0];
UpDown_RegAddress.Minimum = 0;
UpDown_RegAddress.Maximum = 65536;
} }
void App_FormClosed(object sender, FormClosedEventArgs e) void App_FormClosed(object sender, FormClosedEventArgs e)
{ {
@@ -49,12 +62,13 @@ namespace Gidrolock_Modbus_Scanner
else ButtonConnect.Text = "Подключиться"; else ButtonConnect.Text = "Подключиться";
} }
private async void ButtonConnect_Click(object sender, EventArgs e) async Task SendMessageAsync(FunctionCode functionCode, ushort address, ushort length)
{ {
if (CBox_Ports.Text == "") if (CBox_Ports.Text == "")
MessageBox.Show("Необходимо выбрать COM порт.", "Ошибка", MessageBoxButtons.OK); MessageBox.Show("Необходимо выбрать COM порт.", "Ошибка", MessageBoxButtons.OK);
if (UpDown_ModbusID.Value == 0) if (UpDown_ModbusID.Value == 0)
MessageBox.Show("Глобальное вещание пока не поддерживается"); MessageBox.Show("Глобальное вещание пока не поддерживается");
try try
{ {
if (port.IsOpen) if (port.IsOpen)
@@ -67,19 +81,29 @@ namespace Gidrolock_Modbus_Scanner
port.DataBits = 8; port.DataBits = 8;
port.StopBits = StopBits.One; port.StopBits = StopBits.One;
port.ReadTimeout = 10; port.ReadTimeout = 1000;
port.WriteTimeout = 10; port.WriteTimeout = 1000;
offset = 0;
data = new byte[255];
port.Open(); port.Open();
var send = await Modbus.ReadRegAsync(port, (byte)FunctionCode.HoldingRegister, (byte)UpDown_ModbusID.Value, 128, 1);
byte[] message = new byte[8];
Modbus.BuildMessage((byte)UpDown_ModbusID.Value, (byte)(1 + functionCode), address, length, ref message);
string messageParsed = Modbus.ParseByteArray(message);
var send = await Modbus.ReadRegAsync(port, functionCode, (byte)UpDown_ModbusID.Value, address, length);
AddLog("Отправка сообщения: " + messageParsed);
isAwaitingResponse = true; isAwaitingResponse = true;
Task timer = Task.Delay(2000); Task timer = Task.Delay(2000);
await timer.ContinueWith(_ => await timer.ContinueWith(_ =>
{ {
if (isAwaitingResponse) if (isAwaitingResponse)
{
MessageBox.Show("Истекло время ожидания ответа.", "Ошибка"); MessageBox.Show("Истекло время ожидания ответа.", "Ошибка");
port.Close();
}
}); });
} }
@@ -90,6 +114,11 @@ namespace Gidrolock_Modbus_Scanner
} }
} }
private async void ButtonConnect_Click(object sender, EventArgs e)
{
await SendMessageAsync(FunctionCode.HoldingRegister, 128, 1);
}
void CBox_Ports_Click(object sender, EventArgs e) void CBox_Ports_Click(object sender, EventArgs e)
{ {
CBox_Ports.Items.Clear(); CBox_Ports.Items.Clear();
@@ -100,40 +129,37 @@ namespace Gidrolock_Modbus_Scanner
{ {
Console.WriteLine("Data receieved on Serial Port"); Console.WriteLine("Data receieved on Serial Port");
isAwaitingResponse = false; isAwaitingResponse = false;
int len;
byte rdxLen = 0;
try try
{ {
len = port.BytesToRead; int len = port.BytesToRead;
byte[] data = new byte[len]; Console.WriteLine("Data length: " + len);
port.Read(data, rdxLen, len); port.Read(data, offset, len);
rdxLen += (byte)len; offset += len;
int lastByte = len - 1; string dataCleaned = Modbus.ParseByteArray(data);
for (int i = len - 1; i >= 0; i--)
{ TextBox_Log.Invoke((MethodInvoker)delegate { AddLog("Получен ответ: " + dataCleaned); });
if (data[i] != 0) //MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK);
{
lastByte = i;
break;
}
}
string dataString = BitConverter.ToString(data);
string dataCleaned = "";
for (int i = 0; i < dataString.Length; i++)
{
if (dataString[i] == '-')
dataCleaned += " ";
else dataCleaned += dataString[i];
}
MessageBox.Show("Получен ответ от устройства: " + dataCleaned, "Успех", MessageBoxButtons.OK);
} }
catch (Exception err) catch (Exception err)
{ {
MessageBox.Show(err.Message); MessageBox.Show(err.Message);
} }
//port.Close();
port.Close(); }
void AddLog(string message)
{
TextBox_Log.AppendText(Environment.NewLine + message);
}
private async void Button_SendCommand_Click(object sender, EventArgs e)
{
FunctionCode functionCode = (FunctionCode)CBox_Function.SelectedIndex;
ushort address = (ushort)UpDown_RegAddress.Value;
ushort length = (ushort)UpDown_RegLength.Value;
await SendMessageAsync(functionCode, address, length);
} }
} }
} }

View File

@@ -83,6 +83,7 @@
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </Compile>
<None Include=".gitignore" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -92,6 +93,7 @@
<DependentUpon>Settings.settings</DependentUpon> <DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile> </Compile>
<None Include="README.md" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="App.config" /> <None Include="App.config" />

View File

@@ -42,7 +42,7 @@ namespace Gidrolock_Modbus_Scanner
#endregion #endregion
#region Build Message #region Build Message
static void BuildMessage(byte address, byte type, ushort start, ushort registers, ref byte[] message) public static void BuildMessage(byte address, byte type, ushort start, ushort length, ref byte[] message)
{ {
//Array to receive CRC bytes: //Array to receive CRC bytes:
byte[] CRC = new byte[2]; byte[] CRC = new byte[2];
@@ -51,8 +51,8 @@ namespace Gidrolock_Modbus_Scanner
message[1] = type; message[1] = type;
message[2] = (byte)(start >> 8); message[2] = (byte)(start >> 8);
message[3] = (byte)start; message[3] = (byte)start;
message[4] = (byte)(registers >> 8); message[4] = (byte)(length >> 8);
message[5] = (byte)registers; message[5] = (byte)length;
GetCRC(message, ref CRC); GetCRC(message, ref CRC);
message[message.Length - 2] = CRC[0]; message[message.Length - 2] = CRC[0];
@@ -62,51 +62,22 @@ namespace Gidrolock_Modbus_Scanner
} }
#endregion #endregion
#region Check Response
static bool CheckResponse(byte[] response)
{
//Perform a basic CRC check:
byte[] CRC = new byte[2];
GetCRC(response, ref CRC);
if (CRC[0] == response[response.Length - 2] && CRC[1] == response[response.Length - 1])
return true;
else
return false;
}
#endregion
#region Get Response
static void GetResponse(SerialPort port, ref byte[] response)
{
Console.WriteLine("Got response from port");
if (port.BytesToRead == 0)
return;
//There is a bug in .Net 2.0 DataReceived Event that prevents people from using this
//event as an interrupt to handle data (it doesn't fire all of the time). Therefore
//we have to use the ReadByte command for a fixed length as it's been shown to be reliable.
for (int i = 0; i < response.Length; i++)
{
response[i] = (byte)(port.ReadByte());
}
}
#endregion
#region Function 3 - Read Holding Registers #region Function 3 - Read Holding Registers
public static async Task<bool> ReadRegAsync(SerialPort port, byte regType, byte address, ushort start, ushort registers) public static async Task<bool> ReadRegAsync(SerialPort port, FunctionCode functionCode, byte address, ushort start, ushort length)
{ {
short[] values = new short[8];
//Ensure port is open: //Ensure port is open:
if (port.IsOpen) if (port.IsOpen)
{ {
//Clear in/out buffers: //Clear in/out buffers:
port.DiscardOutBuffer(); port.DiscardOutBuffer();
port.DiscardInBuffer(); port.DiscardInBuffer();
//Function 3 request is always 8 bytes:
//Read functions are always 8 bytes long
byte[] message = new byte[8]; byte[] message = new byte[8];
//Function 3 response buffer:
byte[] response = new byte[5 + 2 * registers];
//Build outgoing modbus message: //Build outgoing modbus message:
BuildMessage(address, (byte)3, start, registers, ref message); BuildMessage(address, (byte)(1 + (int)functionCode), start, length, ref message);
//Send modbus message to Serial Port: //Send modbus message to Serial Port:
try try
{ {
@@ -129,6 +100,39 @@ namespace Gidrolock_Modbus_Scanner
} }
#endregion #endregion
/// <summary>
/// Parses a byte array into a string.
/// </summary>
/// <param name="command"></param>
/// <returns>string</returns>
public static string ParseByteArray(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];
string dataString = BitConverter.ToString(res);
string result = "";
for (int i = 0; i < dataString.Length; i++)
{
if (dataString[i] == '-')
result += " ";
else result += dataString[i];
}
return result;
}
} }
} }