using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using static EasyModbus.TCPHandler; namespace McProtocol.Mitsubishi { public class McProtocolTcp { /// /// 使用的指令框架 /// public McFrame CommandFrame { get; set; } private McCommand Command { get; set; } /// /// 主机名或者IP地址 /// public string HostName { get; set; } /// /// 端口号 /// public int PortNumber { get; set; } public int Device { private set; get; } private const int BlockSize = 0x0010; private TcpClient Client { get; set; } private NetworkStream Stream { get; set; } // 是否连接 public bool Connected { get { return Client.Connected; } } /// /// 构造函数 /// public McProtocolTcp() : this("", 0, McFrame.MC3E) { } /// /// 构造函数 /// /// /// /// public McProtocolTcp(string iHostName, int iPortNumber, McFrame frame) { CommandFrame = frame; Client = new TcpClient(); //C70 = MC3E HostName = iHostName; PortNumber = iPortNumber; } /// /// 后处理 /// public void Dispose() { TcpClient c = Client; if (c.Connected) { c.Close(); } } public void Open() { if (!Client.Connected) { // 实现Keep Alive功能 var ka = new List(sizeof(uint) * 3); ka.AddRange(BitConverter.GetBytes(1u)); ka.AddRange(BitConverter.GetBytes(45000u)); ka.AddRange(BitConverter.GetBytes(5000u)); Client.Client.IOControl(IOControlCode.KeepAliveValues, ka.ToArray(), null); IAsyncResult asyncResult = Client.BeginConnect(HostName, PortNumber, null, null); if (!asyncResult.AsyncWaitHandle.WaitOne(1000)) { throw new Exception("连接超时"); } Client.EndConnect(asyncResult); Stream = Client.GetStream(); } Command = new McCommand(CommandFrame); } public int SetBitDevice(string iDeviceName, int iSize, int[] iData) { PlcDeviceType type; int addr; GetDeviceCode(iDeviceName, out type, out addr); return SetBitDevice(type, addr, iSize, iData); } public int SetBitDevice(PlcDeviceType iType, int iAddress, int iSize, int[] iData) { var type = iType; var addr = iAddress; var data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, (byte)iSize, (byte)(iSize >> 8) }; var d = (byte)iData[0]; var i = 0; while (i < iData.Length) { if (i % 2 == 0) { d = (byte)iData[i]; d <<= 4; } else { d |= (byte)(iData[i] & 0x01); data.Add(d); } ++i; } if (i % 2 != 0) { data.Add(d); } int length = (int)Command.FrameType;// == McFrame.MC3E) ? 11 : 15; byte[] sdCommand = Command.SetCommandMC3E(0x1401, 0x0001, data.ToArray()); byte[] rtResponse = TryExecution(sdCommand, length); int rtCode = Command.SetResponse(rtResponse); return rtCode; } public int GetBitDevice(string iDeviceName, int iSize, int[] oData) { PlcDeviceType type; int addr; GetDeviceCode(iDeviceName, out type, out addr); return GetBitDevice(type, addr, iSize, oData); } public int GetBitDevice(PlcDeviceType iType, int iAddress, int iSize, int[] oData) { PlcDeviceType type = iType; int addr = iAddress; var data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, (byte)iSize, (byte)(iSize >> 8) }; byte[] sdCommand = Command.SetCommandMC3E(0x0401, 0x0001, data.ToArray()); int length = (Command.FrameType == McFrame.MC3E) ? 11 : 15; byte[] rtResponse = TryExecution(sdCommand, length); int rtCode = Command.SetResponse(rtResponse); byte[] rtData = Command.Response; for (int i = 0; i < iSize; ++i) { if (i % 2 == 0) { oData[i] = (rtCode == 0) ? ((rtData[i / 2] >> 4) & 0x01) : 0; } else { oData[i] = (rtCode == 0) ? (rtData[i / 2] & 0x01) : 0; } } return rtCode; } public int WriteDeviceBlock(string iDeviceName, int iSize, ushort[] iData) { PlcDeviceType type; int addr; GetDeviceCode(iDeviceName, out type, out addr); return WriteDeviceBlock(type, addr, iSize, iData); } public int WriteDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, ushort[] iData) { PlcDeviceType type = iType; int addr = iAddress; List data; List DeviceData = new List(); foreach (ushort t in iData) { byte[] value = BitConverter.GetBytes(t); if (BitConverter.IsLittleEndian) { Array.Reverse(value); } DeviceData.AddRange(value); } byte[] sdCommand; int length; switch (CommandFrame) { case McFrame.MC3E: data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, (byte)iSize, (byte)(iSize >> 8) }; data.AddRange(DeviceData.ToArray()); sdCommand = Command.SetCommandMC3E(0x1401, 0x0000, data.ToArray()); length = 11; break; case McFrame.MC4E: data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, (byte)iSize, (byte)(iSize >> 8) }; data.AddRange(DeviceData.ToArray()); sdCommand = Command.SetCommandMC4E(0x1401, 0x0000, data.ToArray()); length = 15; break; case McFrame.MC1E: data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)(addr >> 24), 0x20, 0x44, (byte)iSize, 0x00 }; data.AddRange(DeviceData.ToArray()); //Add data sdCommand = Command.SetCommandMC1E(0x03, data.ToArray()); length = 2; break; default: throw new Exception("Message frame not supported"); } //TEST take care of the writing byte[] rtResponse = TryExecution(sdCommand, length); int rtCode = Command.SetResponse(rtResponse); return rtCode; } public byte[] ReadDeviceBlock(string iDeviceName, int iSize, ushort[] oData) { PlcDeviceType type; int addr; GetDeviceCode(iDeviceName, out type, out addr); return ReadDeviceBlock(type, addr, iSize, oData); } public byte[] ReadDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, ushort[] oData) { PlcDeviceType type = iType; int addr = iAddress; List data; byte[] sdCommand; int length; switch (CommandFrame) { case McFrame.MC3E: data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, (byte)iSize, (byte)(iSize >> 8) }; sdCommand = Command.SetCommandMC3E(0x0401, 0x0000, data.ToArray()); length = 11; break; case McFrame.MC4E: data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, (byte)iSize, (byte)(iSize >> 8) }; sdCommand = Command.SetCommandMC4E(0x0401, 0x0000, data.ToArray()); length = 15; break; case McFrame.MC1E: data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)(addr >> 24), 0x20, 0x44, (byte)iSize, 0x00 }; sdCommand = Command.SetCommandMC1E(0x01, data.ToArray()); length = 2; break; default: throw new Exception("Message frame not supported"); } byte[] rtResponse = TryExecution(sdCommand, length); int rtCode = Command.SetResponse(rtResponse); byte[] rtData = Command.Response; for (int i = 0; i < iSize; ++i) { if (rtCode == 0) { oData[i] = (ushort)(rtData[i * 2] << 8 | rtData[i * 2 + 1]); } //oData[i] = (rtCode == 0) ? BitConverter.ToUInt16(rtData, i * 2) : 0; } return rtData; } public int SetDevice(string iDeviceName, int iData) { PlcDeviceType type; int addr; GetDeviceCode(iDeviceName, out type, out addr); return SetDevice(type, addr, iData); } public int SetDevice(PlcDeviceType iType, int iAddress, int iData) { PlcDeviceType type = iType; int addr = iAddress; var data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, 0x01, 0x00, (byte)iData, (byte)(iData >> 8) }; byte[] sdCommand = Command.SetCommandMC3E(0x1401, 0x0000, data.ToArray()); int length = (Command.FrameType == McFrame.MC3E) ? 11 : 15; byte[] rtResponse = TryExecution(sdCommand, length); int rtCode = Command.SetResponse(rtResponse); return rtCode; } public int GetDevice(string iDeviceName) { PlcDeviceType type; int addr; GetDeviceCode(iDeviceName, out type, out addr); return GetDevice(type, addr); } public int GetDevice(PlcDeviceType iType, int iAddress) { PlcDeviceType type = iType; int addr = iAddress; var data = new List(6) { (byte)addr, (byte)(addr >> 8), (byte)(addr >> 16), (byte)type, 0x01, 0x00 }; byte[] sdCommand = Command.SetCommandMC3E(0x0401, 0x0000, data.ToArray()); int length = (Command.FrameType == McFrame.MC3E) ? 11 : 15; byte[] rtResponse = TryExecution(sdCommand, length); int rtCode = Command.SetResponse(rtResponse); if (0 < rtCode) { this.Device = 0; } else { byte[] rtData = Command.Response; this.Device = BitConverter.ToInt16(rtData, 0); } return rtCode; } #region IPlcEx /// /// 得到字节数据 /// /// 如:M1000 /// 读取长度:>0 /// 数据 public int[] GetBitDevice(string iDeviceName, int iSize = 1) { int[] oData = new int[iSize]; GetBitDevice(iDeviceName, iSize, oData); return oData; } /// /// 得到字节数据 /// /// 设备类型,如:M /// 如:M1000 /// 读取长度:>0 /// 数据 public int[] GetBitDevice(PlcDeviceType iType, int iAddress, int iSize = 1) { int[] oData = new int[iSize]; GetBitDevice(iType, iAddress, iSize, oData); return oData; } /// /// 设置字节数据 /// /// 如:M1000 /// 设置的数据 public void SetBitDevice(string iDeviceName, params int[] iData) { SetBitDevice(iDeviceName, iData.Length, iData); } /// /// 设置字节数据 /// /// 设备类型,如:M /// 如:M1000 /// 设置的数据 public void SetBitDevice(PlcDeviceType iType, int iAddress, params int[] iData) { SetBitDevice(iType, iAddress, iData.Length, iData); } /// /// 得到数据块 /// /// 如:D1000 /// 读取长度:>0 /// 数据 public ushort[] ReadDeviceBlock(string iDeviceName, int iSize = 1) { ushort[] oData = new ushort[iSize]; ReadDeviceBlock(iDeviceName, iSize, oData); return oData; } /// /// 得到数据块 /// /// 设备类型,如:D /// 如:D1000 /// 读取长度:>0 /// 数据 public ushort[] ReadDeviceBlock(PlcDeviceType iType, int iAddress, int iSize = 1) { ushort[] oData = new ushort[iSize]; ReadDeviceBlock(iType, iAddress, iSize, oData); return oData; } /// /// 写入数据块 /// /// 如:D1000 /// 写入10进制数据 public void WriteDeviceBlock(string iDeviceName, params ushort[] iData) { WriteDeviceBlock(iDeviceName, iData.Length, iData); } /// /// 写入数据块 /// /// 设备类型,如:D /// 如:D1000 /// 写入10进制数据 public void WriteDeviceBlock(PlcDeviceType iType, int iAddress, params ushort[] iData) { WriteDeviceBlock(iType, iAddress, iData.Length, iData); } #endregion //public int GetCpuType(out string oCpuName, out int oCpuType) //{ // int rtCode = Command.Execute(0x0101, 0x0000, new byte[0]); // oCpuName = "dummy"; // oCpuType = 0; // return rtCode; //} public PlcDeviceType GetDeviceType(string s) { return (s == "M") ? PlcDeviceType.M : (s == "SM") ? PlcDeviceType.SM : (s == "L") ? PlcDeviceType.L : (s == "F") ? PlcDeviceType.F : (s == "V") ? PlcDeviceType.V : (s == "S") ? PlcDeviceType.S : (s == "X") ? PlcDeviceType.X : (s == "Y") ? PlcDeviceType.Y : (s == "B") ? PlcDeviceType.B : (s == "SB") ? PlcDeviceType.SB : (s == "DX") ? PlcDeviceType.DX : (s == "DY") ? PlcDeviceType.DY : (s == "D") ? PlcDeviceType.D : (s == "SD") ? PlcDeviceType.SD : (s == "R") ? PlcDeviceType.R : (s == "ZR") ? PlcDeviceType.ZR : (s == "W") ? PlcDeviceType.W : (s == "SW") ? PlcDeviceType.SW : (s == "TC") ? PlcDeviceType.TC : (s == "TS") ? PlcDeviceType.TS : (s == "TN") ? PlcDeviceType.TN : (s == "CC") ? PlcDeviceType.CC : (s == "CS") ? PlcDeviceType.CS : (s == "CN") ? PlcDeviceType.CN : (s == "SC") ? PlcDeviceType.SC : (s == "SS") ? PlcDeviceType.SS : (s == "SN") ? PlcDeviceType.SN : (s == "Z") ? PlcDeviceType.Z : (s == "TT") ? PlcDeviceType.TT : (s == "TM") ? PlcDeviceType.TM : (s == "CT") ? PlcDeviceType.CT : (s == "CM") ? PlcDeviceType.CM : (s == "A") ? PlcDeviceType.A : PlcDeviceType.Max; } public static bool IsBitDevice(PlcDeviceType type) { return !((type == PlcDeviceType.D) || (type == PlcDeviceType.SD) || (type == PlcDeviceType.Z) || (type == PlcDeviceType.ZR) || (type == PlcDeviceType.R) || (type == PlcDeviceType.W)); } public bool IsHexDevice(PlcDeviceType type) { return (type == PlcDeviceType.X) || (type == PlcDeviceType.Y) || (type == PlcDeviceType.B) || (type == PlcDeviceType.W); } public void GetDeviceCode(string iDeviceName, out PlcDeviceType oType, out int oAddress) { string s = iDeviceName.ToUpper(); string strAddress; // 1.取出一个字符 string strType = s.Substring(0, 1); switch (strType) { case "A": case "B": case "D": case "F": case "L": case "M": case "R": case "V": case "W": case "X": case "Y": // 2字母后面,它应该是一个数字,所以转换它 strAddress = s.Substring(1); break; case "Z": // 再拿出一个字符 strType = s.Substring(0, 2); // 对于文件寄存器 : 2 // 对于索引寄存器 : 1 strAddress = s.Substring(strType.Equals("ZR") ? 2 : 1); break; case "C": // 再拿出一个字符 strType = s.Substring(0, 2); switch (strType) { case "CC": case "CM": case "CN": case "CS": case "CT": strAddress = s.Substring(2); break; default: throw new Exception("Invalid format."); } break; case "S": // 再拿出一个字符 strType = s.Substring(0, 2); switch (strType) { case "SD": case "SM": strAddress = s.Substring(2); break; default: throw new Exception("Invalid format."); } break; case "T": // 再拿出一个字符 strType = s.Substring(0, 2); switch (strType) { case "TC": case "TM": case "TN": case "TS": case "TT": strAddress = s.Substring(2); break; default: throw new Exception("Invalid format."); } break; default: throw new Exception("Invalid format."); } oType = GetDeviceType(strType); oAddress = IsHexDevice(oType) ? Convert.ToInt32(strAddress, BlockSize) : Convert.ToInt32(strAddress); } private byte[] TryExecution(byte[] iCommand, int minlength) { byte[] rtResponse; int tCount = 10; do { rtResponse = Execute(iCommand); --tCount; if (tCount < 0) { throw new Exception("无法从 PLC 获取正确的值."); } } while (Command.IsIncorrectResponse(rtResponse, minlength)); return rtResponse; } // 表示用于通信的命令的内部类 class McCommand { public McFrame FrameType { get; private set; } // 框架类型 private uint SerialNumber { get; set; } // 序号 private uint NetworkNumber { get; set; } // 网络号码 private uint PcNumber { get; set; } // 电脑号码 private uint IoNumber { get; set; } // 请求单元 I/O 编号/O番号 private uint ChannelNumber { get; set; } // 请求单位站号 private uint CpuTimer { get; set; } // 中央处理器监控计时器 private int ResultCode { get; set; } // 退出代码 public byte[] Response { get; private set; } // 响应数据 // 构造 函数 public McCommand(McFrame iFrame) { FrameType = iFrame; SerialNumber = 0x0001u; NetworkNumber = 0x0000u; PcNumber = 0x00FFu; IoNumber = 0x03FFu; ChannelNumber = 0x0000u; CpuTimer = 0x0010u; } public byte[] SetCommandMC1E(byte Subheader, byte[] iData) { List ret = new List(iData.Length + 4); ret.Add(Subheader); ret.Add((byte)this.PcNumber); ret.Add((byte)CpuTimer); ret.Add((byte)(CpuTimer >> 8)); ret.AddRange(iData); return ret.ToArray(); } public byte[] SetCommandMC3E(uint iMainCommand, uint iSubCommand, byte[] iData) { var dataLength = (uint)(iData.Length + 6); List ret = new List(iData.Length + 20); uint frame = 0x0050u; ret.Add((byte)frame); ret.Add((byte)(frame >> 8)); ret.Add((byte)NetworkNumber); ret.Add((byte)PcNumber); ret.Add((byte)IoNumber); ret.Add((byte)(IoNumber >> 8)); ret.Add((byte)ChannelNumber); ret.Add((byte)dataLength); ret.Add((byte)(dataLength >> 8)); ret.Add((byte)CpuTimer); ret.Add((byte)(CpuTimer >> 8)); ret.Add((byte)iMainCommand); ret.Add((byte)(iMainCommand >> 8)); ret.Add((byte)iSubCommand); ret.Add((byte)(iSubCommand >> 8)); ret.AddRange(iData); return ret.ToArray(); } public byte[] SetCommandMC4E(uint iMainCommand, uint iSubCommand, byte[] iData) { var dataLength = (uint)(iData.Length + 6); var ret = new List(iData.Length + 20); uint frame = 0x0054u; ret.Add((byte)frame); ret.Add((byte)(frame >> 8)); ret.Add((byte)SerialNumber); ret.Add((byte)(SerialNumber >> 8)); ret.Add(0x00); ret.Add(0x00); ret.Add((byte)NetworkNumber); ret.Add((byte)PcNumber); ret.Add((byte)IoNumber); ret.Add((byte)(IoNumber >> 8)); ret.Add((byte)ChannelNumber); ret.Add((byte)dataLength); ret.Add((byte)(dataLength >> 8)); ret.Add((byte)CpuTimer); ret.Add((byte)(CpuTimer >> 8)); ret.Add((byte)iMainCommand); ret.Add((byte)(iMainCommand >> 8)); ret.Add((byte)iSubCommand); ret.Add((byte)(iSubCommand >> 8)); ret.AddRange(iData); return ret.ToArray(); } public int SetResponse(byte[] iResponse) { int min; switch (FrameType) { case McFrame.MC1E: min = 2; if (min <= iResponse.Length) { ResultCode = (int)iResponse[min - 2]; Response = new byte[iResponse.Length - 2]; Buffer.BlockCopy(iResponse, min, Response, 0, Response.Length); } break; case McFrame.MC3E: min = 11; if (min <= iResponse.Length) { var btCount = new[] { iResponse[min - 4], iResponse[min - 3] }; var btCode = new[] { iResponse[min - 2], iResponse[min - 1] }; int rsCount = BitConverter.ToUInt16(btCount, 0); ResultCode = BitConverter.ToUInt16(btCode, 0); Response = new byte[rsCount - 2]; Buffer.BlockCopy(iResponse, min, Response, 0, Response.Length); } break; case McFrame.MC4E: min = 15; if (min <= iResponse.Length) { var btCount = new[] { iResponse[min - 4], iResponse[min - 3] }; var btCode = new[] { iResponse[min - 2], iResponse[min - 1] }; int rsCount = BitConverter.ToUInt16(btCount, 0); ResultCode = BitConverter.ToUInt16(btCode, 0); Response = new byte[rsCount - 2]; Buffer.BlockCopy(iResponse, min, Response, 0, Response.Length); } break; default: throw new Exception("Frame type not supported."); } return ResultCode; } public bool IsIncorrectResponse(byte[] iResponse, int minLenght) { //TEST add 1E frame switch (this.FrameType) { case McFrame.MC1E: return ((iResponse.Length < minLenght)); case McFrame.MC3E: case McFrame.MC4E: var btCount = new[] { iResponse[minLenght - 4], iResponse[minLenght - 3] }; var btCode = new[] { iResponse[minLenght - 2], iResponse[minLenght - 1] }; var rsCount = BitConverter.ToUInt16(btCount, 0) - 2; var rsCode = BitConverter.ToUInt16(btCode, 0); return (rsCode == 0 && rsCount != (iResponse.Length - minLenght)); default: throw new Exception("Type Not supported"); } } } private readonly object balanceLock = new object(); protected byte[] Execute(byte[] iCommand) { lock (balanceLock) { List list = new List(); NetworkStream ns = Stream; ns.Write(iCommand, 0, iCommand.Length); ns.Flush(); using (var ms = new MemoryStream()) { var buff = new byte[256]; do { int sz = ns.Read(buff, 0, buff.Length); if (sz == 0) { throw new Exception("已断开连接"); } ms.Write(buff, 0, sz); } while (ns.DataAvailable); return ms.ToArray(); } } } #region INT16 public short ReadInt16(string address) { try { return ReadInt16(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public short[] ReadInt16(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count);//一个地址2个字节 short[] values = new short[count]; for (int i = 0; i < count; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToInt16(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteInt16(string address, short value) { try { WriteInt16(address, new short[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteInt16(string address, short[] value) { try { ushort[] values = new ushort[value.Length]; for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToUInt16(data, 0); } WriteDeviceBlock(address, values); } catch (Exception e) { throw new Exception(e.Message); } } #endregion #region UINT16 public ushort ReadUInt16(string address) { try { return ReadUInt16(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public ushort[] ReadUInt16(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count);//一个地址2个字节 ushort[] values = new ushort[count]; for (int i = 0; i < count; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToUInt16(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteUInt16(string address, ushort value) { try { WriteUInt16(address, new ushort[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteUInt16(string address, ushort[] value) { try { ushort[] values = new ushort[value.Length]; for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToUInt16(data, 0); } WriteDeviceBlock(address, values); } catch (Exception e) { throw new Exception(e.Message); } } #endregion #region INT32 public int ReadInt32(string address) { try { return ReadInt32(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public int[] ReadInt32(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count * 2);//一个地址2个字节 int[] values = new int[count]; for (int i = 0; i < count; i++) { byte[] data1 = BitConverter.GetBytes(value[2 * i + 0]); byte[] data2 = BitConverter.GetBytes(value[2 * i + 1]); List list = new List(); list.AddRange(data1); list.AddRange(data2); byte[] data = list.ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToInt32(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteInt32(string address, int value) { try { WriteInt32(address, new int[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteInt32(string address, int[] value) { try { List values = new List(); for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } ushort value1 = BitConverter.ToUInt16(data, 0); ushort value2 = BitConverter.ToUInt16(data, 2); values.Add(value1); values.Add(value2); } WriteDeviceBlock(address, values.ToArray()); } catch (Exception e) { throw new Exception(e.Message); } } #endregion #region UINT32 public uint ReadUInt32(string address) { try { return ReadUInt32(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public uint[] ReadUInt32(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count * 2);//一个地址2个字节 uint[] values = new uint[count]; for (int i = 0; i < count; i++) { byte[] data1 = BitConverter.GetBytes(value[2 * i + 0]); byte[] data2 = BitConverter.GetBytes(value[2 * i + 1]); List list = new List(); list.AddRange(data1); list.AddRange(data2); byte[] data = list.ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToUInt32(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteUInt32(string address, uint value) { try { WriteUInt32(address, new uint[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteUInt32(string address, uint[] value) { try { List values = new List(); for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } ushort value1 = BitConverter.ToUInt16(data, 0); ushort value2 = BitConverter.ToUInt16(data, 2); values.Add(value1); values.Add(value2); } WriteDeviceBlock(address, values.ToArray()); } catch (Exception e) { throw new Exception(e.Message); } } #endregion #region FLOAT public float ReadFloat(string address) { try { return ReadFloat(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public float[] ReadFloat(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count * 2);//一个地址2个字节 float[] values = new float[count]; for (int i = 0; i < count; i++) { byte[] data1 = BitConverter.GetBytes(value[2 * i + 0]); byte[] data2 = BitConverter.GetBytes(value[2 * i + 1]); List list = new List(); list.AddRange(data1); list.AddRange(data2); byte[] data = list.ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToSingle(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteFloat(string address, float value) { try { WriteFloat(address, new float[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteFloat(string address, float[] value) { try { List values = new List(); for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } ushort value1 = BitConverter.ToUInt16(data, 0); ushort value2 = BitConverter.ToUInt16(data, 2); values.Add(value1); values.Add(value2); } WriteDeviceBlock(address, values.ToArray()); } catch (Exception e) { throw new Exception(e.Message); } } #endregion #region Double public double ReadDouble(string address) { try { return ReadDouble(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public double[] ReadDouble(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count * 4); double[] values = new double[count]; for (int i = 0; i < count; i++) { byte[] data1 = BitConverter.GetBytes(value[4 * i + 0]); byte[] data2 = BitConverter.GetBytes(value[4 * i + 1]); byte[] data3 = BitConverter.GetBytes(value[4 * i + 2]); byte[] data4 = BitConverter.GetBytes(value[4 * i + 3]); List list = new List(); list.AddRange(data1); list.AddRange(data2); list.AddRange(data3); list.AddRange(data4); byte[] data = list.ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToDouble(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteDouble(string address, double value) { try { WriteDouble(address, new double[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteDouble(string address, double[] value) { try { List values = new List(); for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } ushort value1 = BitConverter.ToUInt16(data, 0); ushort value2 = BitConverter.ToUInt16(data, 2); ushort value3 = BitConverter.ToUInt16(data, 4); ushort value4 = BitConverter.ToUInt16(data, 6); values.Add(value1); values.Add(value2); values.Add(value3); values.Add(value4); } WriteDeviceBlock(address, values.ToArray()); } catch (Exception e) { throw new Exception(e.Message); } } #endregion #region Int64 public long ReadInt64(string address) { try { return ReadInt64(address, 1)[0]; } catch (Exception e) { throw new Exception(e.Message); } } public long[] ReadInt64(string address, int count = 1) { try { //地址解析 ushort[] value = ReadDeviceBlock(address, count * 4); long[] values = new long[count]; for (int i = 0; i < count; i++) { byte[] data1 = BitConverter.GetBytes(value[4 * i + 0]); byte[] data2 = BitConverter.GetBytes(value[4 * i + 1]); byte[] data3 = BitConverter.GetBytes(value[4 * i + 2]); byte[] data4 = BitConverter.GetBytes(value[4 * i + 3]); List list = new List(); list.AddRange(data1); list.AddRange(data2); list.AddRange(data3); list.AddRange(data4); byte[] data = list.ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } values[i] = BitConverter.ToInt64(data, 0); } return values; } catch (Exception e) { throw new Exception(e.Message); } } public void WriteInt64(string address, long value) { try { WriteInt64(address, new long[] { value }); } catch (Exception e) { throw new Exception(e.Message); } } public void WriteInt64(string address, long[] value) { try { List values = new List(); for (int i = 0; i < value.Length; i++) { byte[] data = BitConverter.GetBytes(value[i]); if (BitConverter.IsLittleEndian) { Array.Reverse(data); } ushort value1 = BitConverter.ToUInt16(data, 0); ushort value2 = BitConverter.ToUInt16(data, 2); ushort value3 = BitConverter.ToUInt16(data, 4); ushort value4 = BitConverter.ToUInt16(data, 6); values.Add(value1); values.Add(value2); values.Add(value3); values.Add(value4); } WriteDeviceBlock(address, values.ToArray()); } catch (Exception e) { throw new Exception(e.Message); } } #endregion } public enum McFrame { MC1E = 4, MC3E = 11, MC4E = 15 } /// /// 定义 PLC 设备类型的枚举 /// public enum PlcDeviceType { // PLC设备 M = 0x90 , SM = 0x91 , L = 0x92 , F = 0x93 , V = 0x94 , S = 0x98 , X = 0x9C , Y = 0x9D , B = 0xA0 , SB = 0xA1 , DX = 0xA2 , DY = 0xA3 , D = 0xA8 , SD = 0xA9 , R = 0xAF , ZR = 0xB0 , W = 0xB4 , SW = 0xB5 , TC = 0xC0 , TS = 0xC1 , TN = 0xC2 , CC = 0xC3 , CS = 0xC4 , CN = 0xC5 , SC = 0xC6 , SS = 0xC7 , SN = 0xC8 , Z = 0xCC , TT , TM , CT , CM , A , Max } }