1
0
mirror of https://github.com/zhaopeiym/IoTClient synced 2025-10-12 21:20:37 +08:00

新增ModBusRtu服务的仿真模拟

This commit is contained in:
BennyZhao 2019-11-02 17:22:03 +08:00
parent 96542221ec
commit f5a0df8e58
19 changed files with 666 additions and 208 deletions

View File

@ -1,5 +1,4 @@
using IoTClient.Clients.ModBus;
using IoTServer.Common;
using System.Net;
using System.Threading.Tasks;
using Xunit;

View File

@ -40,6 +40,7 @@
this.label4 = new System.Windows.Forms.Label();
this.button6 = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.rd_discrete = new System.Windows.Forms.RadioButton();
this.rd_float = new System.Windows.Forms.RadioButton();
this.rd_double = new System.Windows.Forms.RadioButton();
this.rd_short = new System.Windows.Forms.RadioButton();
@ -58,13 +59,15 @@
this.txt_dataBit = new System.Windows.Forms.TextBox();
this.cb_portNameSend = new System.Windows.Forms.ComboBox();
this.but_close = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.but_server_close = new System.Windows.Forms.Button();
this.but_server_open = new System.Windows.Forms.Button();
this.but_open = new System.Windows.Forms.Button();
this.label5 = new System.Windows.Forms.Label();
this.txt_stationNumber = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.cb_portNameSend_server = new System.Windows.Forms.ComboBox();
this.label8 = new System.Windows.Forms.Label();
this.groupBox3.SuspendLayout();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
@ -104,7 +107,7 @@
this.but_write.TabIndex = 10;
this.but_write.Text = "写入";
this.but_write.UseVisualStyleBackColor = true;
this.but_write.Click += new System.EventHandler(this.butWrite_Click);
this.but_write.Click += new System.EventHandler(this.but_write_Click);
//
// txt_value
//
@ -158,6 +161,7 @@
//
// groupBox1
//
this.groupBox1.Controls.Add(this.rd_discrete);
this.groupBox1.Controls.Add(this.button6);
this.groupBox1.Controls.Add(this.rd_float);
this.groupBox1.Controls.Add(this.rd_double);
@ -174,10 +178,20 @@
this.groupBox1.TabIndex = 32;
this.groupBox1.TabStop = false;
//
// rd_discrete
//
this.rd_discrete.AutoSize = true;
this.rd_discrete.Location = new System.Drawing.Point(64, 23);
this.rd_discrete.Name = "rd_discrete";
this.rd_discrete.Size = new System.Drawing.Size(47, 16);
this.rd_discrete.TabIndex = 24;
this.rd_discrete.Text = "离散";
this.rd_discrete.UseVisualStyleBackColor = true;
//
// rd_float
//
this.rd_float.AutoSize = true;
this.rd_float.Location = new System.Drawing.Point(436, 23);
this.rd_float.Location = new System.Drawing.Point(486, 23);
this.rd_float.Name = "rd_float";
this.rd_float.Size = new System.Drawing.Size(53, 16);
this.rd_float.TabIndex = 22;
@ -187,7 +201,7 @@
// rd_double
//
this.rd_double.AutoSize = true;
this.rd_double.Location = new System.Drawing.Point(495, 23);
this.rd_double.Location = new System.Drawing.Point(545, 23);
this.rd_double.Name = "rd_double";
this.rd_double.Size = new System.Drawing.Size(59, 16);
this.rd_double.TabIndex = 23;
@ -198,7 +212,7 @@
//
this.rd_short.AutoSize = true;
this.rd_short.Checked = true;
this.rd_short.Location = new System.Drawing.Point(70, 23);
this.rd_short.Location = new System.Drawing.Point(120, 23);
this.rd_short.Name = "rd_short";
this.rd_short.Size = new System.Drawing.Size(53, 16);
this.rd_short.TabIndex = 6;
@ -219,7 +233,7 @@
// rd_ulong
//
this.rd_ulong.AutoSize = true;
this.rd_ulong.Location = new System.Drawing.Point(374, 23);
this.rd_ulong.Location = new System.Drawing.Point(424, 23);
this.rd_ulong.Name = "rd_ulong";
this.rd_ulong.Size = new System.Drawing.Size(53, 16);
this.rd_ulong.TabIndex = 21;
@ -229,7 +243,7 @@
// rd_ushort
//
this.rd_ushort.AutoSize = true;
this.rd_ushort.Location = new System.Drawing.Point(129, 23);
this.rd_ushort.Location = new System.Drawing.Point(179, 23);
this.rd_ushort.Name = "rd_ushort";
this.rd_ushort.Size = new System.Drawing.Size(59, 16);
this.rd_ushort.TabIndex = 17;
@ -239,7 +253,7 @@
// rd_long
//
this.rd_long.AutoSize = true;
this.rd_long.Location = new System.Drawing.Point(315, 23);
this.rd_long.Location = new System.Drawing.Point(365, 23);
this.rd_long.Name = "rd_long";
this.rd_long.Size = new System.Drawing.Size(47, 16);
this.rd_long.TabIndex = 20;
@ -249,7 +263,7 @@
// rd_int
//
this.rd_int.AutoSize = true;
this.rd_int.Location = new System.Drawing.Point(194, 23);
this.rd_int.Location = new System.Drawing.Point(244, 23);
this.rd_int.Name = "rd_int";
this.rd_int.Size = new System.Drawing.Size(41, 16);
this.rd_int.TabIndex = 18;
@ -259,7 +273,7 @@
// rd_uint
//
this.rd_uint.AutoSize = true;
this.rd_uint.Location = new System.Drawing.Point(253, 23);
this.rd_uint.Location = new System.Drawing.Point(303, 23);
this.rd_uint.Name = "rd_uint";
this.rd_uint.Size = new System.Drawing.Size(47, 16);
this.rd_uint.TabIndex = 19;
@ -268,7 +282,7 @@
//
// txt_baudRate
//
this.txt_baudRate.Location = new System.Drawing.Point(131, 19);
this.txt_baudRate.Location = new System.Drawing.Point(127, 19);
this.txt_baudRate.Name = "txt_baudRate";
this.txt_baudRate.Size = new System.Drawing.Size(42, 21);
this.txt_baudRate.TabIndex = 5;
@ -286,14 +300,16 @@
//
// groupBox2
//
this.groupBox2.Controls.Add(this.cb_portNameSend_server);
this.groupBox2.Controls.Add(this.label8);
this.groupBox2.Controls.Add(this.label7);
this.groupBox2.Controls.Add(this.txt_stopBit);
this.groupBox2.Controls.Add(this.label6);
this.groupBox2.Controls.Add(this.txt_dataBit);
this.groupBox2.Controls.Add(this.cb_portNameSend);
this.groupBox2.Controls.Add(this.but_close);
this.groupBox2.Controls.Add(this.button2);
this.groupBox2.Controls.Add(this.button1);
this.groupBox2.Controls.Add(this.but_server_close);
this.groupBox2.Controls.Add(this.but_server_open);
this.groupBox2.Controls.Add(this.but_open);
this.groupBox2.Controls.Add(this.label5);
this.groupBox2.Controls.Add(this.txt_stationNumber);
@ -309,7 +325,7 @@
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(253, 23);
this.label7.Location = new System.Drawing.Point(250, 23);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(41, 12);
this.label7.TabIndex = 21;
@ -317,7 +333,7 @@
//
// txt_stopBit
//
this.txt_stopBit.Location = new System.Drawing.Point(296, 19);
this.txt_stopBit.Location = new System.Drawing.Point(292, 19);
this.txt_stopBit.Name = "txt_stopBit";
this.txt_stopBit.Size = new System.Drawing.Size(24, 21);
this.txt_stopBit.TabIndex = 22;
@ -326,7 +342,7 @@
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(178, 24);
this.label6.Location = new System.Drawing.Point(176, 24);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(41, 12);
this.label6.TabIndex = 19;
@ -334,7 +350,7 @@
//
// txt_dataBit
//
this.txt_dataBit.Location = new System.Drawing.Point(219, 20);
this.txt_dataBit.Location = new System.Drawing.Point(217, 20);
this.txt_dataBit.Name = "txt_dataBit";
this.txt_dataBit.Size = new System.Drawing.Size(24, 21);
this.txt_dataBit.TabIndex = 20;
@ -343,14 +359,14 @@
// cb_portNameSend
//
this.cb_portNameSend.FormattingEnabled = true;
this.cb_portNameSend.Location = new System.Drawing.Point(35, 20);
this.cb_portNameSend.Location = new System.Drawing.Point(34, 20);
this.cb_portNameSend.Name = "cb_portNameSend";
this.cb_portNameSend.Size = new System.Drawing.Size(47, 20);
this.cb_portNameSend.TabIndex = 18;
//
// but_close
//
this.but_close.Location = new System.Drawing.Point(419, 19);
this.but_close.Location = new System.Drawing.Point(466, 19);
this.but_close.Name = "but_close";
this.but_close.Size = new System.Drawing.Size(75, 23);
this.but_close.TabIndex = 17;
@ -360,25 +376,27 @@
//
// button2
//
this.button2.Location = new System.Drawing.Point(768, 19);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 16;
this.button2.Text = "关闭服务";
this.button2.UseVisualStyleBackColor = true;
this.but_server_close.Location = new System.Drawing.Point(768, 19);
this.but_server_close.Name = "button2";
this.but_server_close.Size = new System.Drawing.Size(75, 23);
this.but_server_close.TabIndex = 16;
this.but_server_close.Text = "关闭服务";
this.but_server_close.UseVisualStyleBackColor = true;
this.but_server_close.Click += new System.EventHandler(this.but_close_server_Click);
//
// button1
//
this.button1.Location = new System.Drawing.Point(663, 19);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(99, 23);
this.button1.TabIndex = 0;
this.button1.Text = "本地模拟服务";
this.button1.UseVisualStyleBackColor = true;
this.but_server_open.Location = new System.Drawing.Point(665, 19);
this.but_server_open.Name = "button1";
this.but_server_open.Size = new System.Drawing.Size(99, 23);
this.but_server_open.TabIndex = 0;
this.but_server_open.Text = "本地模拟服务";
this.but_server_open.UseVisualStyleBackColor = true;
this.but_server_open.Click += new System.EventHandler(this.but_open_server_Click);
//
// but_open
//
this.but_open.Location = new System.Drawing.Point(338, 18);
this.but_open.Location = new System.Drawing.Point(385, 18);
this.but_open.Name = "but_open";
this.but_open.Size = new System.Drawing.Size(75, 23);
this.but_open.TabIndex = 1;
@ -389,7 +407,7 @@
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(528, 23);
this.label5.Location = new System.Drawing.Point(324, 23);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(29, 12);
this.label5.TabIndex = 15;
@ -397,9 +415,9 @@
//
// txt_stationNumber
//
this.txt_stationNumber.Location = new System.Drawing.Point(563, 19);
this.txt_stationNumber.Location = new System.Drawing.Point(353, 19);
this.txt_stationNumber.Name = "txt_stationNumber";
this.txt_stationNumber.Size = new System.Drawing.Size(35, 21);
this.txt_stationNumber.Size = new System.Drawing.Size(25, 21);
this.txt_stationNumber.TabIndex = 14;
this.txt_stationNumber.Text = "1";
//
@ -415,12 +433,29 @@
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(90, 24);
this.label2.Location = new System.Drawing.Point(86, 24);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(41, 12);
this.label2.TabIndex = 4;
this.label2.Text = "波特率";
//
// cb_portNameSend_server
//
this.cb_portNameSend_server.FormattingEnabled = true;
this.cb_portNameSend_server.Location = new System.Drawing.Point(614, 21);
this.cb_portNameSend_server.Name = "cb_portNameSend_server";
this.cb_portNameSend_server.Size = new System.Drawing.Size(47, 20);
this.cb_portNameSend_server.TabIndex = 24;
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(587, 25);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(29, 12);
this.label8.TabIndex = 23;
this.label8.Text = "端口";
//
// ModBusRtuControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@ -468,8 +503,8 @@
private System.Windows.Forms.TextBox txt_content;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Button but_close;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button but_server_close;
private System.Windows.Forms.Button but_server_open;
private System.Windows.Forms.Button but_open;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox txt_stationNumber;
@ -480,5 +515,8 @@
private System.Windows.Forms.TextBox txt_stopBit;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox txt_dataBit;
private System.Windows.Forms.RadioButton rd_discrete;
private System.Windows.Forms.ComboBox cb_portNameSend_server;
private System.Windows.Forms.Label label8;
}
}

View File

@ -1,20 +1,16 @@
using IoTClient.Clients.ModBus;
using IoTServer.Servers.ModBus;
using System;
using System.Drawing;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;
namespace IoTClient.Tool.Controls
{
public partial class ModBusRtuControl : UserControl
{
/// <summary>
/// 串行端口对象
/// </summary>
//private SerialPort serialPort;
private ModBusRtuClient modBusRtuClient;
private ModBusRtuClient client;
private ModBusRtuServer server;
public ModBusRtuControl()
{
InitializeComponent();
@ -29,10 +25,11 @@ namespace IoTClient.Tool.Controls
txt_content.Location = new Point(13, 160);
but_read.Enabled = false;
but_write.Enabled = false;
button2.Enabled = false;
but_server_close.Enabled = false;
but_close.Enabled = false;
UpdatePortNames();
cb_portNameSend.DropDownStyle = ComboBoxStyle.DropDownList;
cb_portNameSend_server.DropDownStyle = ComboBoxStyle.DropDownList;
}
/// <summary>
@ -40,9 +37,15 @@ namespace IoTClient.Tool.Controls
/// </summary>
public void UpdatePortNames()
{
cb_portNameSend.DataSource = SerialPort.GetPortNames();
cb_portNameSend.DataSource = ModBusRtuClient.GetPortNames();
cb_portNameSend_server.DataSource = ModBusRtuClient.GetPortNames();
}
/// <summary>
/// 打开连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void but_open_Click(object sender, EventArgs e)
{
try
@ -51,9 +54,9 @@ namespace IoTClient.Tool.Controls
var BaudRate = int.Parse(txt_baudRate.Text.ToString());
var DataBits = int.Parse(txt_dataBit.Text.ToString());
var StopBits = (StopBits)int.Parse(txt_stopBit.Text.ToString());
if (modBusRtuClient == null) modBusRtuClient = new ModBusRtuClient(PortName, BaudRate, DataBits, StopBits);
var result = modBusRtuClient.Open();
client?.Close();
client = new ModBusRtuClient(PortName, BaudRate, DataBits, StopBits);
var result = client.Open();
if (result.IsSucceed)
{
but_open.Enabled = false;
@ -66,7 +69,6 @@ namespace IoTClient.Tool.Controls
}
else
AppendText($"连接失败:{result.Err}");
UpdatePortNames();
}
catch (Exception ex)
{
@ -74,22 +76,101 @@ namespace IoTClient.Tool.Controls
}
}
private void AppendText(string content)
{
txt_content.Invoke((Action)(() =>
{
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]{content}\r\n");
}));
}
/// <summary>
/// 发送数据
/// 关闭连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void butWrite_Click(object sender, EventArgs e)
private void butClose_Click(object sender, EventArgs e)
{
var address = txt_address.Text?.Trim();
client?.Close();
AppendText("关闭连接");
but_open.Enabled = true;
but_close.Enabled = false;
cb_portNameSend.Enabled = true;
}
/// <summary>
/// 读数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void but_read_Click(object sender, EventArgs e)
{
byte.TryParse(txt_stationNumber.Text?.Trim(), out byte stationNumber);
if (string.IsNullOrWhiteSpace(txt_address.Text))
{
MessageBox.Show("请输入地址");
return;
}
try
{
dynamic result = null;
if (rd_bit.Checked)
{
result = client.ReadCoil(txt_address.Text, stationNumber);
}
else if (rd_short.Checked)
{
result = client.ReadInt16(txt_address.Text, stationNumber);
}
else if (rd_ushort.Checked)
{
result = client.ReadUInt16(txt_address.Text, stationNumber);
}
else if (rd_int.Checked)
{
result = client.ReadInt32(txt_address.Text, stationNumber);
}
else if (rd_uint.Checked)
{
result = client.ReadUInt32(txt_address.Text, stationNumber);
}
else if (rd_long.Checked)
{
result = client.ReadInt64(txt_address.Text, stationNumber);
}
else if (rd_ulong.Checked)
{
result = client.ReadUInt64(txt_address.Text, stationNumber);
}
else if (rd_float.Checked)
{
result = client.ReadFloat(txt_address.Text, stationNumber);
}
else if (rd_double.Checked)
{
result = client.ReadDouble(txt_address.Text, stationNumber);
}
else if (rd_discrete.Checked)
{
result = client.ReadDiscrete(txt_address.Text, stationNumber);
}
if (result.IsSucceed)
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][读取 {txt_address.Text?.Trim()} 成功]{result.Value}\r\n");
else
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][读取 {txt_address.Text?.Trim()} 失败]{result.Err}\r\n");
if (checkBox1.Checked)
{
txt_content.AppendText($"[请求报文]{result.Requst}\r\n");
txt_content.AppendText($"[响应报文]{result.Response}\r\n\r\n");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 写数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void but_write_Click(object sender, EventArgs e)
{
var address = txt_address.Text?.Trim();
byte.TryParse(txt_stationNumber.Text?.Trim(), out byte stationNumber);
if (string.IsNullOrWhiteSpace(txt_address.Text))
{
@ -119,40 +200,45 @@ namespace IoTClient.Tool.Controls
return;
}
}
result = modBusRtuClient.Write(address, coil, stationNumber);
result = client.Write(address, coil, stationNumber);
}
else if (rd_short.Checked)
{
result = modBusRtuClient.Write(address, short.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, short.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_ushort.Checked)
{
result = modBusRtuClient.Write(address, ushort.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, ushort.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_int.Checked)
{
result = modBusRtuClient.Write(address, int.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, int.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_uint.Checked)
{
result = modBusRtuClient.Write(address, uint.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, uint.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_long.Checked)
{
result = modBusRtuClient.Write(address, long.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, long.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_ulong.Checked)
{
result = modBusRtuClient.Write(address, ulong.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, ulong.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_float.Checked)
{
result = modBusRtuClient.Write(address, float.Parse(txt_value.Text?.Trim()), stationNumber);
result = client.Write(address, float.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_double.Checked)
{
result = modBusRtuClient.Write(address, double.Parse(txt_value.Text?.Trim()), stationNumber);
}
result = client.Write(address, double.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_discrete.Checked)
{
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]离散类型只读\r\n");
return;
}
if (result.IsSucceed)
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][写入 {address?.Trim()} 成功]{txt_value.Text?.Trim()} OK\r\n");
@ -170,76 +256,53 @@ namespace IoTClient.Tool.Controls
}
}
private void butClose_Click(object sender, EventArgs e)
/// <summary>
/// 启动仿真服务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void but_open_server_Click(object sender, EventArgs e)
{
modBusRtuClient?.Close();
AppendText("关闭连接");
but_open.Enabled = true;
but_close.Enabled = false;
}
private void but_read_Click(object sender, EventArgs e)
{
byte.TryParse(txt_stationNumber.Text?.Trim(), out byte stationNumber);
if (string.IsNullOrWhiteSpace(txt_address.Text))
{
MessageBox.Show("请输入地址");
return;
}
try
{
dynamic result = null;
if (rd_bit.Checked)
{
result = modBusRtuClient.ReadCoil(txt_address.Text, stationNumber);
}
else if (rd_short.Checked)
{
result = modBusRtuClient.ReadInt16(txt_address.Text, stationNumber);
}
else if (rd_ushort.Checked)
{
result = modBusRtuClient.ReadUInt16(txt_address.Text, stationNumber);
}
else if (rd_int.Checked)
{
result = modBusRtuClient.ReadInt32(txt_address.Text, stationNumber);
}
else if (rd_uint.Checked)
{
result = modBusRtuClient.ReadUInt32(txt_address.Text, stationNumber);
}
else if (rd_long.Checked)
{
result = modBusRtuClient.ReadInt64(txt_address.Text, stationNumber);
}
else if (rd_ulong.Checked)
{
result = modBusRtuClient.ReadUInt64(txt_address.Text, stationNumber);
}
else if (rd_float.Checked)
{
result = modBusRtuClient.ReadFloat(txt_address.Text, stationNumber);
}
else if (rd_double.Checked)
{
result = modBusRtuClient.ReadDouble(txt_address.Text, stationNumber);
}
if (result.IsSucceed)
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][读取 {txt_address.Text?.Trim()} 成功]{result.Value}\r\n");
else
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][读取 {txt_address.Text?.Trim()} 失败]{result.Err}\r\n");
if (checkBox1.Checked)
{
txt_content.AppendText($"[请求报文]{result.Requst}\r\n");
txt_content.AppendText($"[响应报文]{result.Response}\r\n\r\n");
}
var PortName = cb_portNameSend_server.Text.ToString();
var BaudRate = int.Parse(txt_baudRate.Text.ToString());
var DataBits = int.Parse(txt_dataBit.Text.ToString());
var StopBits = (StopBits)int.Parse(txt_stopBit.Text.ToString());
server?.Stop();
server = new ModBusRtuServer(PortName, BaudRate, DataBits, StopBits);
server.Start();
AppendText("开启仿真服务");
but_server_open.Enabled = false;
but_server_close.Enabled = true;
cb_portNameSend_server.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 关闭仿真服务
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void but_close_server_Click(object sender, EventArgs e)
{
server?.Stop();
AppendText("关闭仿真服务");
but_server_open.Enabled = true;
but_server_close.Enabled = false;
cb_portNameSend_server.Enabled = true;
}
private void AppendText(string content)
{
txt_content.Invoke((Action)(() =>
{
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]{content}\r\n");
}));
}
}
}

View File

@ -61,6 +61,7 @@
this.label4 = new System.Windows.Forms.Label();
this.txt_content = new System.Windows.Forms.TextBox();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.rd_discrete = new System.Windows.Forms.RadioButton();
this.groupBox2.SuspendLayout();
this.groupBox1.SuspendLayout();
this.groupBox3.SuspendLayout();
@ -187,6 +188,7 @@
//
// groupBox1
//
this.groupBox1.Controls.Add(this.rd_discrete);
this.groupBox1.Controls.Add(this.button6);
this.groupBox1.Controls.Add(this.rd_float);
this.groupBox1.Controls.Add(this.rd_double);
@ -216,7 +218,7 @@
// rd_float
//
this.rd_float.AutoSize = true;
this.rd_float.Location = new System.Drawing.Point(436, 23);
this.rd_float.Location = new System.Drawing.Point(486, 23);
this.rd_float.Name = "rd_float";
this.rd_float.Size = new System.Drawing.Size(53, 16);
this.rd_float.TabIndex = 22;
@ -226,7 +228,7 @@
// rd_double
//
this.rd_double.AutoSize = true;
this.rd_double.Location = new System.Drawing.Point(495, 23);
this.rd_double.Location = new System.Drawing.Point(545, 23);
this.rd_double.Name = "rd_double";
this.rd_double.Size = new System.Drawing.Size(59, 16);
this.rd_double.TabIndex = 23;
@ -237,7 +239,7 @@
//
this.rd_short.AutoSize = true;
this.rd_short.Checked = true;
this.rd_short.Location = new System.Drawing.Point(70, 23);
this.rd_short.Location = new System.Drawing.Point(120, 23);
this.rd_short.Name = "rd_short";
this.rd_short.Size = new System.Drawing.Size(53, 16);
this.rd_short.TabIndex = 6;
@ -258,7 +260,7 @@
// rd_ulong
//
this.rd_ulong.AutoSize = true;
this.rd_ulong.Location = new System.Drawing.Point(374, 23);
this.rd_ulong.Location = new System.Drawing.Point(424, 23);
this.rd_ulong.Name = "rd_ulong";
this.rd_ulong.Size = new System.Drawing.Size(53, 16);
this.rd_ulong.TabIndex = 21;
@ -268,7 +270,7 @@
// rd_ushort
//
this.rd_ushort.AutoSize = true;
this.rd_ushort.Location = new System.Drawing.Point(129, 23);
this.rd_ushort.Location = new System.Drawing.Point(179, 23);
this.rd_ushort.Name = "rd_ushort";
this.rd_ushort.Size = new System.Drawing.Size(59, 16);
this.rd_ushort.TabIndex = 17;
@ -278,7 +280,7 @@
// rd_long
//
this.rd_long.AutoSize = true;
this.rd_long.Location = new System.Drawing.Point(315, 23);
this.rd_long.Location = new System.Drawing.Point(365, 23);
this.rd_long.Name = "rd_long";
this.rd_long.Size = new System.Drawing.Size(47, 16);
this.rd_long.TabIndex = 20;
@ -288,7 +290,7 @@
// rd_int
//
this.rd_int.AutoSize = true;
this.rd_int.Location = new System.Drawing.Point(194, 23);
this.rd_int.Location = new System.Drawing.Point(244, 23);
this.rd_int.Name = "rd_int";
this.rd_int.Size = new System.Drawing.Size(41, 16);
this.rd_int.TabIndex = 18;
@ -298,7 +300,7 @@
// rd_uint
//
this.rd_uint.AutoSize = true;
this.rd_uint.Location = new System.Drawing.Point(253, 23);
this.rd_uint.Location = new System.Drawing.Point(303, 23);
this.rd_uint.Name = "rd_uint";
this.rd_uint.Size = new System.Drawing.Size(47, 16);
this.rd_uint.TabIndex = 19;
@ -382,6 +384,16 @@
this.txt_content.Size = new System.Drawing.Size(855, 272);
this.txt_content.TabIndex = 27;
//
// radioButton1
//
this.rd_discrete.AutoSize = true;
this.rd_discrete.Location = new System.Drawing.Point(64, 23);
this.rd_discrete.Name = "radioButton1";
this.rd_discrete.Size = new System.Drawing.Size(47, 16);
this.rd_discrete.TabIndex = 24;
this.rd_discrete.Text = "离散";
this.rd_discrete.UseVisualStyleBackColor = true;
//
// ModBusTcpControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@ -437,5 +449,6 @@
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.RadioButton rd_discrete;
}
}

View File

@ -32,7 +32,7 @@ namespace IoTClient.Tool
private void button1_Click(object sender, EventArgs e)
{
server?.Close();
server?.Stop();
server = new ModBusTcpServer(502);
server.Start();
button1.Enabled = false;
@ -42,7 +42,7 @@ namespace IoTClient.Tool
private void button2_Click(object sender, EventArgs e)
{
server?.Close();
server?.Stop();
button1.Enabled = true;
button2.Enabled = false;
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]关闭仿真模拟服务\r\n");
@ -120,6 +120,10 @@ namespace IoTClient.Tool
{
result = client.ReadDouble(txt_address.Text, stationNumber);
}
else if (rd_discrete.Checked)
{
result = client.ReadDiscrete(txt_address.Text, stationNumber);
}
if (result.IsSucceed)
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][读取 {txt_address.Text?.Trim()} 成功]{result.Value}\r\n");
@ -202,7 +206,11 @@ namespace IoTClient.Tool
{
result = client.Write(txt_address.Text, double.Parse(txt_value.Text?.Trim()), stationNumber);
}
else if (rd_discrete.Checked)
{
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]离散类型只读\r\n");
return;
}
if (result.IsSucceed)
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}][写入 {txt_address.Text?.Trim()} 成功]{txt_value.Text?.Trim()} OK\r\n");

View File

@ -31,7 +31,7 @@ namespace IoTClient.Tool
private void but_server_Click(object sender, EventArgs e)
{
server?.Close();
server?.Stop();
server = new SiemensServer(int.Parse(txt_port.Text.Trim()));
server.Start();
but_server.Enabled = false;
@ -41,7 +41,7 @@ namespace IoTClient.Tool
private void button2_Click(object sender, EventArgs e)
{
server?.Close();
server?.Stop();
but_server.Enabled = true;
button2.Enabled = false;
txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]关闭仿真模拟服务\r\n");

View File

@ -182,8 +182,8 @@
//
this.toolStripMenuItem1.ForeColor = System.Drawing.Color.White;
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(87, 21);
this.toolStripMenuItem1.Text = "测试版 0.0.3";
this.toolStripMenuItem1.Size = new System.Drawing.Size(75, 21);
this.toolStripMenuItem1.Text = " 0.0.3";
this.toolStripMenuItem1.Click += new System.EventHandler(this.toolStripMenuItem1_Click);
//
// IndexForm

View File

@ -1,5 +1,5 @@
using IoTClient.Common.Helpers;
using IoTClient.Core;
using IoTClient.Models;
using System;
using System.IO.Ports;
using System.Linq;
@ -47,7 +47,7 @@ namespace IoTClient.Clients.ModBus
/// 获取设备上的COM端口集合
/// </summary>
/// <returns></returns>
public string[] GetPortNames()
public static string[] GetPortNames()
{
return SerialPort.GetPortNames();
}
@ -138,6 +138,19 @@ namespace IoTClient.Clients.ModBus
//3 获取响应报文
var responsePackage = SerialPortRead(serialPort);
if (!responsePackage.Any())
{
result.IsSucceed = false;
result.Err = "响应结果为空,请检查是否连上了服务端";
return result;
}
else if (!CRC16.CheckCRC16(responsePackage))
{
result.IsSucceed = false;
result.Err = "响应结果CRC16验证失败";
return result;
}
byte[] resultData = new byte[responsePackage.Length - 2];
Array.Copy(responsePackage, 0, resultData, 0, resultData.Length);
@ -363,7 +376,30 @@ namespace IoTClient.Clients.ModBus
if (result.IsSucceed)
result.Value = BitConverter.ToBoolean(readResut.Value, 0);
return result;
}
}
/// <summary>
/// 读取离散
/// </summary>
/// <param name="address"></param>
/// <param name="stationNumber"></param>
/// <param name="functionCode"></param>
/// <returns></returns>
public Result<bool> ReadDiscrete(string address, byte stationNumber = 1, byte functionCode = 2)
{
var readResut = Read(address, stationNumber, functionCode);
var result = new Result<bool>()
{
IsSucceed = readResut.IsSucceed,
Err = readResut.Err,
ErrList = readResut.ErrList,
Requst = readResut.Requst,
Response = readResut.Response,
};
if (result.IsSucceed)
result.Value = BitConverter.ToBoolean(readResut.Value, 0);
return result;
}
#endregion
#region Write
@ -385,10 +421,16 @@ namespace IoTClient.Clients.ModBus
serialPort.Write(commandCRC16, 0, commandCRC16.Length);
result.Requst = string.Join(" ", commandCRC16.Select(t => t.ToString("X2")));
//3 获取响应报文
var dataPackage = SerialPortRead(serialPort);
byte[] resultBuffer = new byte[dataPackage.Length - 2];
Array.Copy(dataPackage, 0, resultBuffer, 0, resultBuffer.Length);
result.Response = string.Join(" ", dataPackage.Select(t => t.ToString("X2")));
var responsePackage = SerialPortRead(serialPort);
if (!CRC16.CheckCRC16(responsePackage))
{
result.IsSucceed = false;
result.Err = "响应结果CRC16验证失败";
return result;
}
byte[] resultBuffer = new byte[responsePackage.Length - 2];
Array.Copy(responsePackage, 0, resultBuffer, 0, resultBuffer.Length);
result.Response = string.Join(" ", responsePackage.Select(t => t.ToString("X2")));
}
catch (Exception ex)
{
@ -424,10 +466,16 @@ namespace IoTClient.Clients.ModBus
serialPort.Write(commandCRC16, 0, commandCRC16.Length);
result.Requst = string.Join(" ", commandCRC16.Select(t => t.ToString("X2")));
//3 获取响应报文
var dataPackage = SerialPortRead(serialPort);
byte[] resultBuffer = new byte[dataPackage.Length - 2];
Array.Copy(dataPackage, 0, resultBuffer, 0, resultBuffer.Length);
result.Response = string.Join(" ", dataPackage.Select(t => t.ToString("X2")));
var responsePackage = SerialPortRead(serialPort);
if (!CRC16.CheckCRC16(responsePackage))
{
result.IsSucceed = false;
result.Err = "响应结果CRC16验证失败";
return result;
}
byte[] resultBuffer = new byte[responsePackage.Length - 2];
Array.Copy(responsePackage, 0, resultBuffer, 0, resultBuffer.Length);
result.Response = string.Join(" ", responsePackage.Select(t => t.ToString("X2")));
}
catch (Exception ex)
{

View File

@ -1,4 +1,5 @@
using IoTClient.Core;
using IoTClient.Models;
using System;
using System.Linq;
using System.Net;
@ -73,8 +74,9 @@ namespace IoTClient.Clients.ModBus
var result = new Result<byte[]>();
try
{
var chenkHead = GetCheckHead(functionCode);
//1 获取命令(组装报文)
byte[] command = GetReadCommand(address, stationNumber, functionCode, readLength);
byte[] command = GetReadCommand(address, stationNumber, functionCode, readLength, chenkHead);
result.Requst = string.Join(" ", command.Select(t => t.ToString("X2")));
//2 发送命令
socket.Send(command);
@ -82,13 +84,17 @@ namespace IoTClient.Clients.ModBus
var headPackage = SocketRead(socket, 8);
int length = headPackage[4] * 256 + headPackage[5] - 2;
var dataPackage = SocketRead(socket, length);
byte[] resultBuffer = new byte[dataPackage.Length - 1];
Array.Copy(dataPackage, 1, resultBuffer, 0, resultBuffer.Length);
result.Response = string.Join(" ", headPackage.Concat(dataPackage).Select(t => t.ToString("X2")));
//4 获取响应报文数据(字节数组形式)
result.Value = resultBuffer.Reverse().ToArray();
if (chenkHead[0] != headPackage[0] || chenkHead[1] != headPackage[1])
{
result.IsSucceed = false;
result.Err = "响应结果校验失败";
result.ErrList.Add("响应结果校验失败");
}
}
catch (SocketException ex)
{
@ -319,6 +325,29 @@ namespace IoTClient.Clients.ModBus
result.Value = BitConverter.ToBoolean(readResut.Value, 0);
return result;
}
/// <summary>
/// 读取离散
/// </summary>
/// <param name="address"></param>
/// <param name="stationNumber"></param>
/// <param name="functionCode"></param>
/// <returns></returns>
public Result<bool> ReadDiscrete(string address, byte stationNumber = 1, byte functionCode = 2)
{
var readResut = Read(address, stationNumber, functionCode);
var result = new Result<bool>()
{
IsSucceed = readResut.IsSucceed,
Err = readResut.Err,
ErrList = readResut.ErrList,
Requst = readResut.Requst,
Response = readResut.Response,
};
if (result.IsSucceed)
result.Value = BitConverter.ToBoolean(readResut.Value, 0);
return result;
}
#endregion
#region Write
@ -336,14 +365,21 @@ namespace IoTClient.Clients.ModBus
var result = new Result();
try
{
var command = GetWriteCoilCommand(address, value, stationNumber, functionCode);
var chenkHead = GetCheckHead(functionCode);
var command = GetWriteCoilCommand(address, value, stationNumber, functionCode, chenkHead);
socket.Send(command);
result.Requst = string.Join(" ", command.Select(t => t.ToString("X2")));
//获取响应报文
var headBytes = SocketRead(socket, 8);
int length = headBytes[4] * 256 + headBytes[5] - 2;
var dataBytes = SocketRead(socket, length);
result.Response = string.Join(" ", headBytes.Concat(dataBytes).Select(t => t.ToString("X2")));
var headPackage = SocketRead(socket, 8);
int length = headPackage[4] * 256 + headPackage[5] - 2;
var dataPackage = SocketRead(socket, length);
result.Response = string.Join(" ", headPackage.Concat(dataPackage).Select(t => t.ToString("X2")));
if (chenkHead[0] != headPackage[0] || chenkHead[1] != headPackage[1])
{
result.IsSucceed = false;
result.Err = "响应结果校验失败";
result.ErrList.Add("响应结果校验失败");
}
}
catch (SocketException ex)
{
@ -383,14 +419,21 @@ namespace IoTClient.Clients.ModBus
var result = new Result();
try
{
var command = GetWriteCommand(address, values, stationNumber, functionCode);
var chenkHead = GetCheckHead(functionCode);
var command = GetWriteCommand(address, values, stationNumber, functionCode, chenkHead);
socket.Send(command);
result.Requst = string.Join(" ", command.Select(t => t.ToString("X2")));
//获取响应报文
var headBytes = SocketRead(socket, 8);
int length = headBytes[4] * 256 + headBytes[5] - 2;
var dataBytes = SocketRead(socket, length);
result.Response = string.Join(" ", headBytes.Concat(dataBytes).Select(t => t.ToString("X2")));
var headPackage = SocketRead(socket, 8);
int length = headPackage[4] * 256 + headPackage[5] - 2;
var dataPackage = SocketRead(socket, length);
result.Response = string.Join(" ", headPackage.Concat(dataPackage).Select(t => t.ToString("X2")));
if (chenkHead[0] != headPackage[0] || chenkHead[1] != headPackage[1])
{
result.IsSucceed = false;
result.Err = "响应结果校验失败";
result.ErrList.Add("响应结果校验失败");
}
}
catch (SocketException ex)
{
@ -522,6 +565,16 @@ namespace IoTClient.Clients.ModBus
#region
/// <summary>
/// 获取随机校验头
/// </summary>
/// <returns></returns>
private byte[] GetCheckHead(int seed)
{
var random = new Random(DateTime.Now.Millisecond + seed);
return new byte[] { (byte)random.Next(255), (byte)random.Next(255) };
}
/// <summary>
/// 获取读取命令
/// </summary>
@ -530,12 +583,12 @@ namespace IoTClient.Clients.ModBus
/// <param name="functionCode">功能码</param>
/// <param name="length">读取长度</param>
/// <returns></returns>
public byte[] GetReadCommand(string address, byte stationNumber, byte functionCode, ushort length)
public byte[] GetReadCommand(string address, byte stationNumber, byte functionCode, ushort length, byte[] check = null)
{
var readAddress = ushort.Parse(address?.Trim());
byte[] buffer = new byte[12];
buffer[0] = 0x19;
buffer[1] = 0xB2;//Client发出的检验信息
buffer[0] = check?[0] ?? 0x19;
buffer[1] = check?[1] ?? 0xB2;//Client发出的检验信息
buffer[2] = 0x00;
buffer[3] = 0x00;//表示tcp/ip 的协议的modbus的协议
buffer[4] = 0x00;
@ -558,12 +611,12 @@ namespace IoTClient.Clients.ModBus
/// <param name="stationNumber">站号</param>
/// <param name="functionCode">功能码</param>
/// <returns></returns>
public byte[] GetWriteCommand(string address, byte[] values, byte stationNumber, byte functionCode)
public byte[] GetWriteCommand(string address, byte[] values, byte stationNumber, byte functionCode, byte[] check = null)
{
var writeAddress = ushort.Parse(address?.Trim());
byte[] buffer = new byte[13 + values.Length];
buffer[0] = 0x19;
buffer[1] = 0xB2;//检验信息用来验证response是否串数据了
buffer[0] = check?[0] ?? 0x19;
buffer[1] = check?[1] ?? 0xB2;//检验信息用来验证response是否串数据了
buffer[4] = BitConverter.GetBytes(7 + values.Length)[1];
buffer[5] = BitConverter.GetBytes(7 + values.Length)[0];//表示的是header handle后面还有多长的字节
@ -586,12 +639,12 @@ namespace IoTClient.Clients.ModBus
/// <param name="stationNumber">站号</param>
/// <param name="functionCode">功能码</param>
/// <returns></returns>
public byte[] GetWriteCoilCommand(string address, bool value, byte stationNumber, byte functionCode)
public byte[] GetWriteCoilCommand(string address, bool value, byte stationNumber, byte functionCode, byte[] check = null)
{
var writeAddress = ushort.Parse(address?.Trim());
byte[] buffer = new byte[12];
buffer[0] = 0x19;
buffer[1] = 0xB2;//Client发出的检验信息
buffer[0] = check?[0] ?? 0x19;
buffer[1] = check?[1] ?? 0xB2;//Client发出的检验信息
buffer[4] = 0x00;
buffer[5] = 0x06;//表示的是该字节以后的字节长度

View File

@ -2,6 +2,7 @@
using IoTClient.Common.Enums;
using IoTClient.Core;
using IoTClient.Core.Models;
using IoTClient.Models;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -149,6 +149,15 @@
<param name="functionCode">功能码</param>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusRtuClient.ReadDiscrete(System.String,System.Byte,System.Byte)">
<summary>
读取离散
</summary>
<param name="address"></param>
<param name="stationNumber"></param>
<param name="functionCode"></param>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusRtuClient.Write(System.String,System.Boolean,System.Byte,System.Byte)">
<summary>
线圈写入
@ -379,6 +388,15 @@
<param name="functionCode">功能码</param>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.ReadDiscrete(System.String,System.Byte,System.Byte)">
<summary>
读取离散
</summary>
<param name="address"></param>
<param name="stationNumber"></param>
<param name="functionCode"></param>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.Write(System.String,System.Boolean,System.Byte,System.Byte)">
<summary>
线圈写入
@ -470,7 +488,13 @@
<param name="stationNumber">站号</param>
<param name="functionCode">功能码</param>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetReadCommand(System.String,System.Byte,System.Byte,System.UInt16)">
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetCheckHead(System.Int32)">
<summary>
获取随机校验头
</summary>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetReadCommand(System.String,System.Byte,System.Byte,System.UInt16,System.Byte[])">
<summary>
获取读取命令
</summary>
@ -480,7 +504,7 @@
<param name="length">读取长度</param>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetWriteCommand(System.String,System.Byte[],System.Byte,System.Byte)">
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetWriteCommand(System.String,System.Byte[],System.Byte,System.Byte,System.Byte[])">
<summary>
获取写入命令
</summary>
@ -490,7 +514,7 @@
<param name="functionCode">功能码</param>
<returns></returns>
</member>
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetWriteCoilCommand(System.String,System.Boolean,System.Byte,System.Byte)">
<member name="M:IoTClient.Clients.ModBus.ModBusTcpClient.GetWriteCoilCommand(System.String,System.Boolean,System.Byte,System.Byte,System.Byte[])">
<summary>
获取线圈写入命令
</summary>
@ -805,42 +829,42 @@
西门子S7-200Smar
</summary>
</member>
<member name="T:IoTClient.Core.Result">
<member name="T:IoTClient.Models.Result">
<summary>
请求结果
</summary>
</member>
<member name="P:IoTClient.Core.Result.IsSucceed">
<member name="P:IoTClient.Models.Result.IsSucceed">
<summary>
是否成功
</summary>
</member>
<member name="P:IoTClient.Core.Result.Err">
<member name="P:IoTClient.Models.Result.Err">
<summary>
异常消息
</summary>
</member>
<member name="P:IoTClient.Core.Result.ErrList">
<member name="P:IoTClient.Models.Result.ErrList">
<summary>
异常集合
</summary>
</member>
<member name="P:IoTClient.Core.Result.Requst">
<member name="P:IoTClient.Models.Result.Requst">
<summary>
请求报文
</summary>
</member>
<member name="P:IoTClient.Core.Result.Response">
<member name="P:IoTClient.Models.Result.Response">
<summary>
响应报文
</summary>
</member>
<member name="T:IoTClient.Core.Result`1">
<member name="T:IoTClient.Models.Result`1">
<summary>
请求结果
</summary>
</member>
<member name="P:IoTClient.Core.Result`1.Value">
<member name="P:IoTClient.Models.Result`1.Value">
<summary>
数据结果
</summary>

View File

@ -0,0 +1,61 @@
using System.Collections.Generic;
namespace IoTClient.Models
{
/// <summary>
/// 请求结果
/// </summary>
public class Result
{
public Result()
{
}
/// <summary>
/// 是否成功
/// </summary>
public bool IsSucceed { get; set; } = true;
/// <summary>
/// 异常消息
/// </summary>
public string Err { get; set; }
/// <summary>
/// 异常集合
/// </summary>
public List<string> ErrList { get; set; } = new List<string>();
/// <summary>
/// 请求报文
/// </summary>
public string Requst { get; set; }
/// <summary>
/// 响应报文
/// </summary>
public string Response { get; set; }
}
/// <summary>
/// 请求结果
/// </summary>
public class Result<T> : Result
{
public Result()
{
}
public Result(T data)
{
Value = data;
}
/// <summary>
/// 数据结果
/// </summary>
public T Value { get; set; }
}
}

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IoTClient.Core.Models
namespace IoTClient.Core.Models
{
public class SiemensData
{

View File

@ -1,4 +1,5 @@
using System;
using IoTClient.Models;
using System;
using System.Net.Sockets;
namespace IoTClient.Core

View File

@ -39,11 +39,33 @@
初始化加载数据
</summary>
</member>
<member name="M:IoTServer.Servers.ModBus.ModBusRtuServer.Start">
<summary>
启动服务
</summary>
</member>
<member name="M:IoTServer.Servers.ModBus.ModBusRtuServer.Stop">
<summary>
停止服务
</summary>
</member>
<member name="M:IoTServer.Servers.ModBus.ModBusRtuServer.DataReceived(System.Object,System.IO.Ports.SerialDataReceivedEventArgs)">
<summary>
接收数据回调用
</summary>
<param name="sender"></param>
<param name="e"></param>
</member>
<member name="M:IoTServer.Servers.ModBus.ModBusTcpServer.Start">
<summary>
启动服务
</summary>
</member>
<member name="M:IoTServer.Servers.ModBus.ModBusTcpServer.Stop">
<summary>
停止服务
</summary>
</member>
<member name="M:IoTServer.Servers.ModBus.ModBusTcpServer.Accept(System.Net.Sockets.Socket)">
<summary>
客户端连接到服务端
@ -61,6 +83,11 @@
启动服务
</summary>
</member>
<member name="M:IoTServer.Servers.PLC.SiemensServer.Stop">
<summary>
停止服务
</summary>
</member>
<member name="M:IoTServer.Servers.PLC.SiemensServer.Accept(System.Net.Sockets.Socket)">
<summary>
客户端连接到服务端

View File

@ -0,0 +1,117 @@
using IoTClient.Common.Helpers;
using IoTServer.Common;
using Newtonsoft.Json;
using System;
using System.IO.Ports;
using System.Linq;
using System.Text;
namespace IoTServer.Servers.ModBus
{
public class ModBusRtuServer
{
private SerialPort serialPort;
DataPersist dataPersist;
public ModBusRtuServer(string portName, int baudRate, int dataBits, StopBits stopBits)
{
if (serialPort == null) serialPort = new SerialPort();
serialPort.PortName = portName;
serialPort.BaudRate = baudRate;
serialPort.DataBits = dataBits;
serialPort.StopBits = stopBits;
serialPort.Encoding = Encoding.ASCII;
#if !DEBUG
serialPort.ReadTimeout = 1000;//1秒
#endif
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived);
dataPersist = new DataPersist("ModBusTcpServer");
}
/// <summary>
/// 启动服务
/// </summary>
public void Start()
{
serialPort.Open();
}
/// <summary>
/// 停止服务
/// </summary>
public void Stop()
{
serialPort.Close();
serialPort.Dispose();
}
/// <summary>
/// 接收数据回调用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
byte[] requetData = new byte[serialPort.BytesToRead];
serialPort.Read(requetData, 0, requetData.Length);
var address = requetData[2] * 256 + requetData[3];
switch (requetData[1])
{
//读取线圈
case 1:
{
var value = dataPersist.Read(address);
var bytes = JsonConvert.DeserializeObject<byte[]>(value).Reverse().ToArray();
var tempData = new byte[4];
tempData[0] = 1;
tempData[1] = 1;
Buffer.BlockCopy(bytes, 0, tempData, 2, 2);
var responseData = CRC16.GetCRC16(tempData);
serialPort.Write(responseData, 0, responseData.Length);
}
break;
//写入线圈
case 5:
{
var value = new byte[2];
Buffer.BlockCopy(requetData, requetData.Length - 4, value, 0, value.Length);
dataPersist.Write(address, JsonConvert.SerializeObject(value));
serialPort.Write(requetData, 0, requetData.Length);
}
break;
//读取
case 3:
{
var value = dataPersist.Read(address);
var bytes = JsonConvert.DeserializeObject<byte[]>(value);
if (bytes == null)
{
var length = requetData[requetData.Length - 4] * 256 + requetData[requetData.Length - 5];
bytes = new byte[length * 2];
}
var dataHead = new byte[] { 1, 3, (byte)bytes.Length };
var tempData = dataHead.Concat(bytes).ToArray();
var responseData = CRC16.GetCRC16(tempData);
serialPort.Write(responseData, 0, responseData.Length);
}
break;
//写入
case 16:
{
var value = new byte[requetData[6]];
Buffer.BlockCopy(requetData, 7, value, 0, value.Length);
dataPersist.Write(address, JsonConvert.SerializeObject(value));
var tempData = new byte[6];
Buffer.BlockCopy(requetData, 0, tempData, 0, tempData.Length);
var responseData = CRC16.GetCRC16(tempData);
serialPort.Write(responseData, 0, responseData.Length);
}
break;
}
}
catch (Exception ex)
{ }
}
}
}

View File

@ -42,7 +42,10 @@ namespace IoTServer.Servers.ModBus
Task.Run(() => { Accept(socketServer); });
}
public void Close()
/// <summary>
/// 停止服务
/// </summary>
public void Stop()
{
if (socketServer?.Connected ?? false)
socketServer.Shutdown(SocketShutdown.Both);
@ -148,7 +151,6 @@ namespace IoTServer.Servers.ModBus
//读取
case 3:
{
var value = dataPersist.Read(address);// 数据存在 8、9
var bytes = JsonConvert.DeserializeObject<byte[]>(value);
if (bytes == null)

View File

@ -44,7 +44,10 @@ namespace IoTServer.Servers.PLC
Task.Run(() => { Accept(socketServer); });
}
public void Close()
/// <summary>
/// 停止服务
/// </summary>
public void Stop()
{
if (socketServer?.Connected ?? false)
socketServer.Shutdown(SocketShutdown.Both);

View File

@ -3,10 +3,14 @@
QQ交流群[995475200](https://jq.qq.com/?_wv=1027&k=5bz0ne5)
# Demo效果图
![image](https://user-images.githubusercontent.com/5820324/67485072-f27aab00-f69b-11e9-9219-0a0ccb4caae0.png)
![image](https://user-images.githubusercontent.com/5820324/68068792-1a50c980-fd94-11e9-9ad6-3c8cf683cf6d.png)
![image](https://user-images.githubusercontent.com/5820324/67485248-3e2d5480-f69c-11e9-8dea-0ef5ebc3369c.png)
![image](https://user-images.githubusercontent.com/5820324/68068801-305e8a00-fd94-11e9-9745-98afa11c968e.png)
![image](https://user-images.githubusercontent.com/5820324/67485565-e3482d00-f69c-11e9-99b1-e86d3c78fcec.png)
![image](https://user-images.githubusercontent.com/5820324/68068805-3c4a4c00-fd94-11e9-899e-cec0b4b70fa8.png)
![image](https://user-images.githubusercontent.com/5820324/67488504-86e80c00-f6a2-11e9-9612-7d92aebb2394.png)
![image](https://user-images.githubusercontent.com/5820324/68068874-bf6ba200-fd94-11e9-817d-62ed251e258f.png)
![image](https://user-images.githubusercontent.com/5820324/68068818-63a11900-fd94-11e9-932e-fa0bd5941861.png)
![image](https://user-images.githubusercontent.com/5820324/68068890-e75b0580-fd94-11e9-9370-b914e5af9590.png)