From c81787446290d8d5bb53a5ef950e7dc1eeafbf79 Mon Sep 17 00:00:00 2001 From: BennyZhao Date: Mon, 6 Jan 2020 08:53:40 +0800 Subject: [PATCH] =?UTF-8?q?S7-200Smart=20=E6=89=B9=E9=87=8F=E8=AF=BB?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IoTClient.Tool/Controls/ModBusRtuControl.cs | 3 +- IoTClient.Tool/Controls/ModBusTcpControl.cs | 24 +- IoTClient.Tool/Controls/OtherControl.cs | 24 ++ .../Controls/SiemensControl.Designer.cs | 23 +- IoTClient.Tool/Controls/SiemensControl.cs | 191 ++++++--- IoTClient.Tool/IndexForm.Designer.cs | 31 +- IoTClient.Tool/IndexForm.cs | 11 +- IoTClient.Tool/Model/VersionCheckInput.cs | 2 +- IoTClient/Clients/PLC/SiemensClient.cs | 372 +++++++++++++++--- IoTClient/IoTClient/IoTClient.xml | 88 +++++ IoTClient/Models/SiemensData.cs | 6 +- IoTServer/Servers/PLC/SiemensServer.cs | 40 +- 12 files changed, 659 insertions(+), 156 deletions(-) diff --git a/IoTClient.Tool/Controls/ModBusRtuControl.cs b/IoTClient.Tool/Controls/ModBusRtuControl.cs index 7c846fa..88f5065 100644 --- a/IoTClient.Tool/Controls/ModBusRtuControl.cs +++ b/IoTClient.Tool/Controls/ModBusRtuControl.cs @@ -359,7 +359,6 @@ namespace IoTClient.Tool.Controls /// 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)) { @@ -373,7 +372,7 @@ namespace IoTClient.Tool.Controls } try { - + var address = txt_address.Text?.Trim().Split('-')[0]; dynamic result = null; if (rd_bit.Checked) { diff --git a/IoTClient.Tool/Controls/ModBusTcpControl.cs b/IoTClient.Tool/Controls/ModBusTcpControl.cs index f34a64f..0aca12b 100644 --- a/IoTClient.Tool/Controls/ModBusTcpControl.cs +++ b/IoTClient.Tool/Controls/ModBusTcpControl.cs @@ -241,7 +241,7 @@ namespace IoTClient.Tool } try { - + var address = txt_address.Text.Split('-')[0]; dynamic result = null; if (rd_bit.Checked) { @@ -257,39 +257,39 @@ namespace IoTClient.Tool return; } } - result = client.Write(txt_address.Text, coil, stationNumber); + result = client.Write(address, coil, stationNumber); } else if (rd_short.Checked) { - result = client.Write(txt_address.Text, short.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, short.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_ushort.Checked) { - result = client.Write(txt_address.Text, ushort.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, ushort.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_int.Checked) { - result = client.Write(txt_address.Text, int.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, int.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_uint.Checked) { - result = client.Write(txt_address.Text, uint.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, uint.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_long.Checked) { - result = client.Write(txt_address.Text, long.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, long.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_ulong.Checked) { - result = client.Write(txt_address.Text, ulong.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, ulong.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_float.Checked) { - result = client.Write(txt_address.Text, float.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, float.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_double.Checked) { - result = client.Write(txt_address.Text, double.Parse(txt_value.Text?.Trim()), stationNumber); + result = client.Write(address, double.Parse(txt_value.Text?.Trim()), stationNumber); } else if (rd_discrete.Checked) { @@ -298,9 +298,9 @@ namespace IoTClient.Tool } if (result.IsSucceed) - AppendText($"[写入 {txt_address.Text?.Trim()} 成功]:{txt_value.Text?.Trim()} OK"); + AppendText($"[写入 {address?.Trim()} 成功]:{txt_value.Text?.Trim()} OK"); else - AppendText($"[写入 {txt_address.Text?.Trim()} 失败]:{result.Err}"); + AppendText($"[写入 {address?.Trim()} 失败]:{result.Err}"); if (chb_show_package.Checked || (ModifierKeys & Keys.Control) == Keys.Control) { AppendText($"[请求报文]{result.Requst}"); diff --git a/IoTClient.Tool/Controls/OtherControl.cs b/IoTClient.Tool/Controls/OtherControl.cs index f0b1cf0..25a0853 100644 --- a/IoTClient.Tool/Controls/OtherControl.cs +++ b/IoTClient.Tool/Controls/OtherControl.cs @@ -22,6 +22,12 @@ namespace IoTClient.Tool.Controls private void but_crc16calculate_Click(object sender, EventArgs e) { + if (string.IsNullOrWhiteSpace(txt_crcstr.Text) || txt_crcstr.Text.Trim().Replace(" ", "").Length % 2 != 0) + { + MessageBox.Show("请传入有效的参数"); + return; + } + var byteArry = DataConvert.StringToByteArray(txt_crcstr.Text?.Trim(), false); var crc16 = CRC16.GetCRC16(byteArry); AppendText($"CRC16计算结果:{DataConvert.ByteArrayToString(crc16)}"); @@ -37,6 +43,12 @@ namespace IoTClient.Tool.Controls private void but_crc16validation_Click(object sender, EventArgs e) { + if (string.IsNullOrWhiteSpace(txt_crcstr.Text) || txt_crcstr.Text.Trim().Replace(" ", "").Length % 2 != 0) + { + MessageBox.Show("请传入有效的参数"); + return; + } + var byteArry = DataConvert.StringToByteArray(txt_crcstr.Text?.Trim(), false); var checkCrc16 = CRC16.CheckCRC16(byteArry); AppendText($"CRC16验证结果:{txt_crcstr.Text} {checkCrc16}"); @@ -54,6 +66,12 @@ namespace IoTClient.Tool.Controls private void but_tcpOpen_Click(object sender, EventArgs e) { + if (string.IsNullOrWhiteSpace(txt_tcpip.Text) || string.IsNullOrWhiteSpace(txt_tcpport.Text)) + { + MessageBox.Show("请传入有效的IP和端口"); + return; + } + socketTcp?.Close(); socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try @@ -113,6 +131,12 @@ namespace IoTClient.Tool.Controls private void but_udpOpen_Click(object sender, EventArgs e) { + if (string.IsNullOrWhiteSpace(txt_tcpip.Text) || string.IsNullOrWhiteSpace(txt_tcpport.Text)) + { + MessageBox.Show("请传入有效的IP和端口"); + return; + } + try { udpClient = new UdpClient(); diff --git a/IoTClient.Tool/Controls/SiemensControl.Designer.cs b/IoTClient.Tool/Controls/SiemensControl.Designer.cs index 634d502..655a252 100644 --- a/IoTClient.Tool/Controls/SiemensControl.Designer.cs +++ b/IoTClient.Tool/Controls/SiemensControl.Designer.cs @@ -59,9 +59,9 @@ this.but_close_server = new System.Windows.Forms.Button(); this.but_close = new System.Windows.Forms.Button(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.rd_byte = new System.Windows.Forms.RadioButton(); this.button3 = new System.Windows.Forms.Button(); this.txt_content = new System.Windows.Forms.TextBox(); - this.rd_byte = new System.Windows.Forms.RadioButton(); this.groupBox3.SuspendLayout(); this.groupBox2.SuspendLayout(); this.groupBox1.SuspendLayout(); @@ -366,6 +366,16 @@ this.groupBox1.TabIndex = 32; this.groupBox1.TabStop = false; // + // rd_byte + // + this.rd_byte.AutoSize = true; + this.rd_byte.Location = new System.Drawing.Point(54, 23); + this.rd_byte.Name = "rd_byte"; + this.rd_byte.Size = new System.Drawing.Size(47, 16); + this.rd_byte.TabIndex = 25; + this.rd_byte.Text = "byte"; + this.rd_byte.UseVisualStyleBackColor = true; + // // button3 // this.button3.Location = new System.Drawing.Point(762, 17); @@ -386,16 +396,6 @@ this.txt_content.Size = new System.Drawing.Size(855, 272); this.txt_content.TabIndex = 31; // - // rd_byte - // - this.rd_byte.AutoSize = true; - this.rd_byte.Location = new System.Drawing.Point(54, 23); - this.rd_byte.Name = "rd_byte"; - this.rd_byte.Size = new System.Drawing.Size(47, 16); - this.rd_byte.TabIndex = 25; - this.rd_byte.Text = "byte"; - this.rd_byte.UseVisualStyleBackColor = true; - // // SiemensControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); @@ -406,6 +406,7 @@ this.Controls.Add(this.txt_content); this.Name = "SiemensControl"; this.Size = new System.Drawing.Size(880, 450); + this.ControlRemoved += new System.Windows.Forms.ControlEventHandler(this.SiemensControl_ControlRemoved); this.groupBox3.ResumeLayout(false); this.groupBox3.PerformLayout(); this.groupBox2.ResumeLayout(false); diff --git a/IoTClient.Tool/Controls/SiemensControl.cs b/IoTClient.Tool/Controls/SiemensControl.cs index 58a085d..e47f2ea 100644 --- a/IoTClient.Tool/Controls/SiemensControl.cs +++ b/IoTClient.Tool/Controls/SiemensControl.cs @@ -47,12 +47,17 @@ namespace IoTClient.Tool but_close_server.Enabled = false; but_close.Enabled = false; but_sendData.Enabled = false; + + toolTip1.SetToolTip(but_open, "点击打开连接"); + toolTip1.SetToolTip(txt_address, "支持批量读取,如V2634-3将会读取V2634、V2638、V2642地址对应的数据"); + txt_content.Text = "小技巧:\r\n1、读取地址支持批量读取,如V2634-3将会读取V2634、V2638、V2642地址对应的数据\r\n"; } private void but_server_Click(object sender, EventArgs e) { try { + if (txt_content.Text.Contains("小技巧")) txt_content.Text = string.Empty; server?.Stop(); server = new SiemensServer(int.Parse(txt_port.Text.Trim())); server.Start(); @@ -78,6 +83,7 @@ namespace IoTClient.Tool { try { + if (txt_content.Text.Contains("小技巧")) txt_content.Text = string.Empty; client?.Close(); client = new SiemensClient(SiemensVersion.S7_200Smart, txt_ip.Text?.Trim(), int.Parse(txt_port.Text.Trim())); var result = client.Open(); @@ -122,51 +128,118 @@ namespace IoTClient.Tool return; } dynamic result = null; - if (rd_byte.Checked) + + //bool类型不进行批量读取 + if (rd_bit.Checked) txt_address.Text = txt_address.Text.Split('-')[0]; + var addressAndReadLength = txt_address.Text.Split('-'); + + //批量读取 + if (addressAndReadLength.Length == 2) { - result = client.ReadByte(txt_address.Text); + var address = addressAndReadLength[0]; + var readNumber = ushort.Parse(addressAndReadLength[1]); + ushort bLength = 1; + if (rd_bit.Checked) + bLength = 2; + else if (rd_byte.Checked) + bLength = 1; + else if (rd_short.Checked || rd_ushort.Checked) + bLength = 2; + else if (rd_int.Checked || rd_uint.Checked || rd_float.Checked) + bLength = 4; + else if (rd_long.Checked || rd_ulong.Checked || rd_double.Checked) + bLength = 8; + + var readLength = Convert.ToUInt16(bLength * readNumber); + + if (!rd_bit.Checked) result = client.Read(address.ToString(), readLength, false); + else result = client.Read(address.ToString(), readLength, true); + + var addressNumber = int.Parse(address.Substring(1)); + if (result.IsSucceed) + { + AppendEmptyText(); + byte[] rValue = result.Value; + rValue = rValue.Reverse().ToArray(); + for (int i = 0; i < readNumber; i++) + { + var cAddress = (addressNumber + i * bLength).ToString(); + + var addressStr = address.Substring(0, 1) + (addressNumber + i * bLength); + if (rd_short.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadInt16(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_ushort.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadUInt16(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_int.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadInt32(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_uint.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadUInt32(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_long.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadInt64(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_ulong.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadUInt64(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_float.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadFloat(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_double.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadDouble(addressNumber.ToString(), cAddress, rValue).Value}"); + else if (rd_byte.Checked) + AppendText($"[读取 {addressStr} 成功]:{ client.ReadByte(addressNumber.ToString(), cAddress, rValue).Value}"); + //else if (rd_bit.Checked) + // AppendText($"[读取 {addressStr} 成功]:{ client.ReadBoolean(addressNumber.ToString(), cAddress, rValue).Value}"); + } + } + else + AppendText($"[读取 {txt_address.Text?.Trim()} 失败]:{result.Err}"); } - else if (rd_bit.Checked) + //单个读取 + else { - result = client.ReadBoolean(txt_address.Text); - } - else if (rd_short.Checked) - { - result = client.ReadInt16(txt_address.Text); - } - else if (rd_ushort.Checked) - { - result = client.ReadUInt16(txt_address.Text); - } - else if (rd_int.Checked) - { - result = client.ReadInt32(txt_address.Text); - } - else if (rd_uint.Checked) - { - result = client.ReadUInt32(txt_address.Text); - } - else if (rd_long.Checked) - { - result = client.ReadInt64(txt_address.Text); - } - else if (rd_ulong.Checked) - { - result = client.ReadUInt64(txt_address.Text); - } - else if (rd_float.Checked) - { - result = client.ReadFloat(txt_address.Text); - } - else if (rd_double.Checked) - { - result = client.ReadDouble(txt_address.Text); + if (rd_byte.Checked) + { + result = client.ReadByte(txt_address.Text); + } + else if (rd_bit.Checked) + { + result = client.ReadBoolean(txt_address.Text); + } + else if (rd_short.Checked) + { + result = client.ReadInt16(txt_address.Text); + } + else if (rd_ushort.Checked) + { + result = client.ReadUInt16(txt_address.Text); + } + else if (rd_int.Checked) + { + result = client.ReadInt32(txt_address.Text); + } + else if (rd_uint.Checked) + { + result = client.ReadUInt32(txt_address.Text); + } + else if (rd_long.Checked) + { + result = client.ReadInt64(txt_address.Text); + } + else if (rd_ulong.Checked) + { + result = client.ReadUInt64(txt_address.Text); + } + else if (rd_float.Checked) + { + result = client.ReadFloat(txt_address.Text); + } + else if (rd_double.Checked) + { + result = client.ReadDouble(txt_address.Text); + } + if (result.IsSucceed) + AppendText($"[读取 {txt_address.Text?.Trim()} 成功]:{result.Value}"); + else + AppendText($"[读取 {txt_address.Text?.Trim()} 失败]:{result.Err}"); } - if (result.IsSucceed) - AppendText($"[读取 {txt_address.Text?.Trim()} 成功]:{result.Value}"); - else - AppendText($"[读取 {txt_address.Text?.Trim()} 失败]:{result.Err}"); if (chb_show_package.Checked || (ModifierKeys & Keys.Control) == Keys.Control) { AppendText($"[请求报文]{result.Requst}"); @@ -200,6 +273,7 @@ namespace IoTClient.Tool try { + var address = txt_address.Text.Split('-')[0]; dynamic result = null; if (rd_bit.Checked) { @@ -215,50 +289,50 @@ namespace IoTClient.Tool return; } } - result = client.Write(txt_address.Text, bit); + result = client.Write(address, bit); } else if (rd_byte.Checked) { - result = client.Write(txt_address.Text, byte.Parse(txt_value.Text?.Trim())); + result = client.Write(address, byte.Parse(txt_value.Text?.Trim())); } else if (rd_short.Checked) { - result = client.Write(txt_address.Text, short.Parse(txt_value.Text?.Trim())); + result = client.Write(address, short.Parse(txt_value.Text?.Trim())); } else if (rd_ushort.Checked) { - result = client.Write(txt_address.Text, ushort.Parse(txt_value.Text?.Trim())); + result = client.Write(address, ushort.Parse(txt_value.Text?.Trim())); } else if (rd_int.Checked) { - result = client.Write(txt_address.Text, int.Parse(txt_value.Text?.Trim())); + result = client.Write(address, int.Parse(txt_value.Text?.Trim())); } else if (rd_uint.Checked) { - result = client.Write(txt_address.Text, uint.Parse(txt_value.Text?.Trim())); + result = client.Write(address, uint.Parse(txt_value.Text?.Trim())); } else if (rd_long.Checked) { - result = client.Write(txt_address.Text, long.Parse(txt_value.Text?.Trim())); + result = client.Write(address, long.Parse(txt_value.Text?.Trim())); } else if (rd_ulong.Checked) { - result = client.Write(txt_address.Text, ulong.Parse(txt_value.Text?.Trim())); + result = client.Write(address, ulong.Parse(txt_value.Text?.Trim())); } else if (rd_float.Checked) { - result = client.Write(txt_address.Text, float.Parse(txt_value.Text?.Trim())); + result = client.Write(address, float.Parse(txt_value.Text?.Trim())); } else if (rd_double.Checked) { - result = client.Write(txt_address.Text, double.Parse(txt_value.Text?.Trim())); + result = client.Write(address, double.Parse(txt_value.Text?.Trim())); } if (result.IsSucceed) - AppendText($"[写入 {txt_address.Text?.Trim()} 成功]:{txt_value.Text?.Trim()} OK"); + AppendText($"[写入 {address?.Trim()} 成功]:{txt_value.Text?.Trim()} OK"); else - AppendText($"[写入 {txt_address.Text?.Trim()} 失败]:{result.Err}"); + AppendText($"[写入 {address?.Trim()} 失败]:{result.Err}"); if (chb_show_package.Checked || (ModifierKeys & Keys.Control) == Keys.Control) { AppendText($"[请求报文]{result.Requst}"); @@ -313,5 +387,18 @@ namespace IoTClient.Tool txt_content.AppendText($"[{DateTime.Now.ToLongTimeString()}]{content}\r\n"); })); } + + private void AppendEmptyText() + { + txt_content.Invoke((Action)(() => + { + txt_content.AppendText($"\r\n"); + })); + } + + private void SiemensControl_ControlRemoved(object sender, ControlEventArgs e) + { + + } } } diff --git a/IoTClient.Tool/IndexForm.Designer.cs b/IoTClient.Tool/IndexForm.Designer.cs index 30ff735..82c5fec 100644 --- a/IoTClient.Tool/IndexForm.Designer.cs +++ b/IoTClient.Tool/IndexForm.Designer.cs @@ -39,6 +39,7 @@ this.OmronFinsTcp = new System.Windows.Forms.TabPage(); this.BACnet = new System.Windows.Forms.TabPage(); this.Ports = new System.Windows.Forms.TabPage(); + this.Other = new System.Windows.Forms.TabPage(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); @@ -46,7 +47,7 @@ this.toolStripMenuItemBlogPath = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem4 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.Other = new System.Windows.Forms.TabPage(); + this.商务合作ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.modBusTcpControl1 = new IoTClient.Tool.ModBusTcpControl(); this.tabControl1.SuspendLayout(); this.ModBusTcp.SuspendLayout(); @@ -164,6 +165,16 @@ this.Ports.Text = " 串口 "; this.Ports.UseVisualStyleBackColor = true; // + // Other + // + this.Other.Location = new System.Drawing.Point(4, 22); + this.Other.Name = "Other"; + this.Other.Padding = new System.Windows.Forms.Padding(3); + this.Other.Size = new System.Drawing.Size(886, 448); + this.Other.TabIndex = 9; + this.Other.Text = "工具"; + this.Other.UseVisualStyleBackColor = true; + // // menuStrip1 // this.menuStrip1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(148)))), ((int)(((byte)(255))))); @@ -173,6 +184,7 @@ this.toolStripMenuItem3, this.toolStripMenuItemBlogPath, this.toolStripMenuItem4, + this.商务合作ToolStripMenuItem, this.toolStripMenuItem1}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; @@ -225,18 +237,16 @@ this.toolStripMenuItem1.ForeColor = System.Drawing.Color.White; this.toolStripMenuItem1.Name = "toolStripMenuItem1"; this.toolStripMenuItem1.Size = new System.Drawing.Size(75, 21); - this.toolStripMenuItem1.Text = "版本 0.3.4"; + this.toolStripMenuItem1.Text = "版本 0.3.5"; this.toolStripMenuItem1.Click += new System.EventHandler(this.toolStripMenuItem1_Click); // - // Other + // 商务合作ToolStripMenuItem // - this.Other.Location = new System.Drawing.Point(4, 22); - this.Other.Name = "Other"; - this.Other.Padding = new System.Windows.Forms.Padding(3); - this.Other.Size = new System.Drawing.Size(886, 448); - this.Other.TabIndex = 9; - this.Other.Text = "工具"; - this.Other.UseVisualStyleBackColor = true; + this.商务合作ToolStripMenuItem.ForeColor = System.Drawing.Color.White; + this.商务合作ToolStripMenuItem.Name = "商务合作ToolStripMenuItem"; + this.商务合作ToolStripMenuItem.Size = new System.Drawing.Size(68, 21); + this.商务合作ToolStripMenuItem.Text = "商务合作"; + this.商务合作ToolStripMenuItem.Click += new System.EventHandler(this.cooperationToolStripMenuItem_Click); // // modBusTcpControl1 // @@ -289,5 +299,6 @@ private System.Windows.Forms.TabPage ModBusAscii; private System.Windows.Forms.TabPage SiemensS7300; private System.Windows.Forms.TabPage Other; + private System.Windows.Forms.ToolStripMenuItem 商务合作ToolStripMenuItem; } } \ No newline at end of file diff --git a/IoTClient.Tool/IndexForm.cs b/IoTClient.Tool/IndexForm.cs index 61173c4..390f8a2 100644 --- a/IoTClient.Tool/IndexForm.cs +++ b/IoTClient.Tool/IndexForm.cs @@ -235,6 +235,15 @@ namespace IoTClient.Tool catch (Exception) { } } + private void cooperationToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + Process.Start("http://wpa.qq.com/msgrd?v=3&uin=1150234111&site=qq&menu=yes"); + } + catch (Exception) { } + } + private void toolStripMenuItem5_Click(object sender, EventArgs e) { try @@ -326,6 +335,6 @@ namespace IoTClient.Tool if (File.Exists(filePath)) File.Delete(filePath); } } - } + } } } diff --git a/IoTClient.Tool/Model/VersionCheckInput.cs b/IoTClient.Tool/Model/VersionCheckInput.cs index 89f1954..122ad3e 100644 --- a/IoTClient.Tool/Model/VersionCheckInput.cs +++ b/IoTClient.Tool/Model/VersionCheckInput.cs @@ -5,7 +5,7 @@ /// /// 当前版本 /// - public float CurrentVersion { get; set; } = 0.34f; + public float CurrentVersion { get; set; } = 0.35f; /// /// 忽略版本 diff --git a/IoTClient/Clients/PLC/SiemensClient.cs b/IoTClient/Clients/PLC/SiemensClient.cs index 5549821..0ac577c 100644 --- a/IoTClient/Clients/PLC/SiemensClient.cs +++ b/IoTClient/Clients/PLC/SiemensClient.cs @@ -121,43 +121,21 @@ namespace IoTClient.Clients.PLC try { //兼容地址,如VD5012中的D - if (address.Length >= 2 && !"0123456789".Contains(address[1].ToString())) - address = address.Remove(1, 1); + if (address.Length >= 2 && !"0123456789".Contains(address[1].ToString())) address = address.Remove(1, 1); //发送读取信息 var arg = ConvertArg(address); byte[] command; if (isBit) - command = GetReadBitCommand(arg.TypeCode, arg.BeginAddress, arg.DbBlock); + command = GetReadBitCommand(arg.TypeCode, arg.BeginAddress, arg.DbBlock, length); else command = GetReadCommand(arg.TypeCode, arg.BeginAddress, arg.DbBlock, length); result.Requst = string.Join(" ", command.Select(t => t.ToString("X2"))); //发送命令 并获取响应报文 var dataPackage = SendPackage(command); - var bufferLength = length == 8 ? 8 : 4; - byte[] temp = new byte[bufferLength]; - byte[] response = new byte[bufferLength]; - Array.Copy(dataPackage, dataPackage.Length - bufferLength, temp, 0, bufferLength); - switch (length) - { - case 8: - response[0] = temp[7]; - response[1] = temp[6]; - response[2] = temp[5]; - response[3] = temp[4]; - response[4] = temp[3]; - response[5] = temp[2]; - response[6] = temp[1]; - response[7] = temp[0]; - break; - default: - response[0] = temp[3]; - response[1] = temp[2]; - response[2] = temp[1]; - response[3] = temp[0]; - break; - } + byte[] responseData = new byte[length]; + Array.Copy(dataPackage, dataPackage.Length - length, responseData, 0, length); result.Response = string.Join(" ", dataPackage.Select(t => t.ToString("X2"))); - result.Value = response; + result.Value = responseData.Reverse().ToArray(); } catch (SocketException ex) { @@ -195,12 +173,11 @@ namespace IoTClient.Clients.PLC try { //兼容地址,如VD5012中的D - if (address.Length >= 2 && !"0123456789".Contains(address[1].ToString())) - address = address.Remove(1, 1); + if (address.Length >= 2 && !"0123456789".Contains(address[1].ToString())) address = address.Remove(1, 1); //发送读取信息 var arg = ConvertArg(address); byte[] command = GetReadCommand(arg.TypeCode, arg.BeginAddress, arg.DbBlock, length); - result.Requst = string.Join(" ", command.Select(t => t.ToString("X2"))); + result.Requst = string.Join(" ", command.Select(t => t.ToString("X2"))); var dataPackage = SendPackage(command); byte[] requst = new byte[length]; Array.Copy(dataPackage, 25, requst, 0, length); @@ -239,7 +216,7 @@ namespace IoTClient.Clients.PLC public Result ReadBoolean(string address) { //return BitConverter.ToBoolean(Read(address, 4, isBit: true), 0); - var readResut = Read(address, 4, isBit: true); + var readResut = Read(address, 1, isBit: true); var result = new Result() { IsSucceed = readResut.IsSucceed, @@ -253,8 +230,13 @@ namespace IoTClient.Clients.PLC return result; } + /// + /// + /// + /// + /// public Result ReadByte(string address) - { + { var readResut = Read(address, 1); var result = new Result() { @@ -483,6 +465,306 @@ namespace IoTClient.Clients.PLC } //return Encoding.ASCII.GetString(, 1, length[0]); } + + ///// + ///// 从批量读取的数据字节提取对应的地址数据 + ///// + ///// 批量读取的起始地址 + ///// 读取地址 + ///// 批量读取的值 + ///// + //public Result ReadBoolean(string beginAddress, string address, byte[] values) + //{ + // if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + // throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + // try + // { + // var i = addressInt - beginAddressInt; + // var byteArry = values.Skip(i).Take(1).ToArray(); + // return new Result + // { + // Value = BitConverter.ToBoolean(byteArry, 0) + // }; + // } + // catch (Exception ex) + // { + // return new Result + // { + // IsSucceed = false, + // Err = ex.Message + // }; + // } + //} + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadByte(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = addressInt - beginAddressInt; + return new Result + { + Value = values.Skip(i).Take(1).ToArray()[0] + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadInt16(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = addressInt - beginAddressInt; + var byteArry = values.Skip(i).Take(2).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToInt16(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadUInt16(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = addressInt - beginAddressInt; + var byteArry = values.Skip(i).Take(2).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToUInt16(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadInt32(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = (addressInt - beginAddressInt) / 2; + var byteArry = values.Skip(i * 2).Take(2 * 2).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToInt32(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadUInt32(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = (addressInt - beginAddressInt) / 2; + var byteArry = values.Skip(i * 2).Take(2 * 2).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToUInt32(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadInt64(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = (addressInt - beginAddressInt) / 4; + var byteArry = values.Skip(i * 4).Take(2 * 4).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToInt64(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadUInt64(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = (addressInt - beginAddressInt) / 4; + var byteArry = values.Skip(i * 4).Take(2 * 4).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToUInt64(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadFloat(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = (addressInt - beginAddressInt) / 2; + var byteArry = values.Skip(i * 2).Take(2 * 2).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToSingle(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } + + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// + public Result ReadDouble(string beginAddress, string address, byte[] values) + { + if (!int.TryParse(address?.Trim(), out int addressInt) || !int.TryParse(beginAddress?.Trim(), out int beginAddressInt)) + throw new Exception($"只能是数字,参数address:{address} beginAddress:{beginAddress}"); + try + { + var i = (addressInt - beginAddressInt) / 4; + var byteArry = values.Skip(i * 4).Take(2 * 4).Reverse().ToArray(); + return new Result + { + Value = BitConverter.ToDouble(byteArry, 0) + }; + } + catch (Exception ex) + { + return new Result + { + IsSucceed = false, + Err = ex.Message + }; + } + } #endregion #region Write @@ -584,7 +866,7 @@ namespace IoTClient.Clients.PLC /// public Result Write(string address, byte value) { - return Write(address, BitConverter.GetBytes(value)); + return Write(address, new byte[1] { value }); } /// @@ -764,23 +1046,23 @@ namespace IoTClient.Clients.PLC command[3] = (byte)(command.Length % 256);//[2][3]整个读取请求长度为0x1F= 31 command[4] = 0x02; command[5] = 0xF0; - command[6] = 0x80; - command[7] = 0x32; + command[6] = 0x80;//COTP + command[7] = 0x32;//协议ID command[8] = 0x01;//1 客户端发送命令 3 服务器回复命令 command[9] = 0x00; command[10] = 0x00;//[4]-[10]固定6个字节 command[11] = 0x00; command[12] = 0x01;//[11][12]两个字节,标识序列号,回复报文相同位置和这个完全一样;范围是0~65535 command[13] = 0x00; - command[14] = 0x0E; + command[14] = 0x0E;//parameter length([17]-[30]都为parameter刚好14也就是0x0E) command[15] = 0x00; - command[16] = 0x00; + command[16] = 0x00;//data length command[17] = 0x04;//04读 05写 command[18] = 0x01;//读取数据块个数 - command[19] = 0x12; - command[20] = 0x0A; - command[21] = 0x10; - command[22] = 0x02; + command[19] = 0x12;//variable specification + command[20] = 0x0A;//Length of following address specification + command[21] = 0x10;//Syntax Id: S7ANY + command[22] = 0x02;//Transport size: BYTE command[23] = (byte)(length / 256); command[24] = (byte)(length % 256);//[23][24]两个字节,访问数据的个数,以byte为单位; command[25] = (byte)(dbAddress / 256); @@ -792,7 +1074,7 @@ namespace IoTClient.Clients.PLC return command; } - protected byte[] GetReadBitCommand(byte type, int beginAddress, ushort dbAddress) + protected byte[] GetReadBitCommand(byte type, int beginAddress, ushort dbAddress, ushort length = 1) { byte[] command = new byte[31]; command[0] = 0x03; @@ -809,7 +1091,7 @@ namespace IoTClient.Clients.PLC command[11] = 0x00; command[12] = 0x01; command[13] = (byte)((command.Length - 17) / 256); - command[14] = (byte)((command.Length - 17) % 256); + command[14] = (byte)((command.Length - 17) % 256); //parameter length(减17是因为从[17]到最后属于parameter) command[15] = 0x00; command[16] = 0x00; command[17] = 0x04;//04读 05写 @@ -818,8 +1100,8 @@ namespace IoTClient.Clients.PLC command[20] = 0x0A; command[21] = 0x10; command[22] = 0x01; - command[23] = 0x00; - command[24] = 0x01; + command[23] = (byte)(length / 256); + command[24] = (byte)(length % 256); command[25] = (byte)(dbAddress / 256); command[26] = (byte)(dbAddress % 256);//[25][26]DB块的编号 command[27] = type;//访问数据块的类型 diff --git a/IoTClient/IoTClient/IoTClient.xml b/IoTClient/IoTClient/IoTClient.xml index 547e545..2609d2d 100644 --- a/IoTClient/IoTClient/IoTClient.xml +++ b/IoTClient/IoTClient/IoTClient.xml @@ -1838,6 +1838,13 @@ 地址 + + + + + + + 读取Int16 @@ -1901,6 +1908,87 @@ 地址 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 写入数据 diff --git a/IoTClient/Models/SiemensData.cs b/IoTClient/Models/SiemensData.cs index 9313c92..15a9a78 100644 --- a/IoTClient/Models/SiemensData.cs +++ b/IoTClient/Models/SiemensData.cs @@ -9,11 +9,7 @@ /// /// DB块编号 /// - public ushort DbBlock { get; set; } - ///// - ///// 读取的数据长度 - ///// - //public ushort Length { get; set; } + public ushort DbBlock { get; set; } /// /// 开始地址 /// diff --git a/IoTServer/Servers/PLC/SiemensServer.cs b/IoTServer/Servers/PLC/SiemensServer.cs index cf190da..f5cb7ac 100644 --- a/IoTServer/Servers/PLC/SiemensServer.cs +++ b/IoTServer/Servers/PLC/SiemensServer.cs @@ -117,28 +117,32 @@ namespace IoTServer.Servers.PLC continue; } var address = requetData[28] * 256 * 256 + requetData[29] * 256 + requetData[30]; + var typeDB = requetData[27]; + var stationNumberKey = $"s200-{typeDB}"; switch (requetData[17]) { //读 case 4: { - var value = dataPersist.Read(address);//TODO 数据存在 25、26 + //读取数据长度 + var readLength = requetData[23] * 256 + requetData[24]; + + var value = dataPersist.Read(stationNumberKey);//TODO 数据存在 25、26 + var byteArray = JsonConvert.DeserializeObject(value) ?? new byte[65536]; //把存储的数据转为字节数组 - var bytes = JsonConvert.DeserializeObject(value); - if (string.IsNullOrWhiteSpace(value)) - bytes = BitConverter.GetBytes(0); - var dataContent = new byte[4 + bytes.Length];//可以从报文中获取Length? + //var bytes = JsonConvert.DeserializeObject(value); + //if (string.IsNullOrWhiteSpace(value)) + // bytes = BitConverter.GetBytes(0); + var dataContent = new byte[4 + readLength];//可以从报文中获取Length? DataConvert.StringToByteArray("FF 09 00 04").CopyTo(dataContent, 0); - dataContent[1] = bytes.Length == 1 ? (byte)0x03 : (byte)0x04;//04 byte(字节) 03bit(位) - dataContent[2] = (byte)(bytes.Length / 256); - dataContent[3] = (byte)(bytes.Length % 256); - //dataContent[0] 固定 + dataContent[1] = readLength == 1 ? (byte)0x03 : (byte)0x04;//04 byte(字节) 03bit(位) + dataContent[2] = (byte)(readLength / 256); + dataContent[3] = (byte)(readLength % 256); + Buffer.BlockCopy(byteArray, address / 8, dataContent, 4, readLength); //dataContent[2] dataContent[3] 后半截数据数组的Length //dataContent[4]-[7] 返回给客户端的数据 byte[] responseData1 = new byte[21 + dataContent.Length]; DataConvert.StringToByteArray("03 00 00 1A 02 F0 80 32 03 00 00 00 01 00 02 00 00 00 00 04 01").CopyTo(responseData1, 0); - //responseData1[0] = 0x03; - //responseData1[1] = 0x00; //固定协议头 //responseData1[8] = 0x03;//1 客户端发送命令 3 服务器回复命令 responseData1[2] = (byte)(responseData1.Length / 256); responseData1[3] = (byte)(responseData1.Length % 256); @@ -147,22 +151,24 @@ namespace IoTServer.Servers.PLC responseData1[20] = requetData[18]; dataContent.CopyTo(responseData1, 21); //当读取的是字符串的时候[25]存储的后面的数据长度,参考SiemensClient的Write(string address, string value)方法。 - Buffer.BlockCopy(bytes, 0, responseData1, responseData1.Length - bytes.Length, bytes.Length); + //Buffer.BlockCopy(bytes, 0, responseData1, responseData1.Length - bytes.Length, bytes.Length); newSocket.Send(responseData1); + } break; //写 case 5: { - var valueByte = new byte[requetData.Length - 35]; - Buffer.BlockCopy(requetData, 35, valueByte, 0, valueByte.Length); + var value = new byte[requetData.Length - 35]; + Buffer.BlockCopy(requetData, 35, value, 0, value.Length); + + var byteArray = JsonConvert.DeserializeObject(dataPersist.Read(stationNumberKey)) ?? new byte[65536]; + value.CopyTo(byteArray, address / 8); //存储字节数据到内存 - dataPersist.Write(address, JsonConvert.SerializeObject(valueByte)); + dataPersist.Write(stationNumberKey, JsonConvert.SerializeObject(byteArray)); byte[] responseData1 = new byte[22]; DataConvert.StringToByteArray("03 00 00 16 02 F0 80 32 03 00 00 00 01 00 02 00 01 00 00 05 01 FF").CopyTo(responseData1, 0); - //responseData1[15] = (byte)(responseData1.Length / 256); - //responseData1[16] = (byte)(responseData1.Length % 256); newSocket.Send(responseData1); } break;