using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using NModbus; namespace Team.Communicate.Modbus { public class ModbusTcpMaster : IModbusTcpMaster { private readonly string _ip; private readonly int _port; public DataFormat DataFormat { get; set; } = DataFormat.CDAB; public int ConnectTimeOut { get; set; } public string Ip { get => _ip; } public int Port { get => _port; } public bool IsConnect { get; private set; } private IModbusMaster _modbusMaster; private TcpClient _client; public event EventHandler ConnectChanged; public ModbusTcpMaster(string ip, int port) { _ip = ip; _port = port; var modbusFactory = new ModbusFactory(); _client = new TcpClient(); _modbusMaster = modbusFactory.CreateMaster(_client); } /// /// client must is connected /// /// public ModbusTcpMaster(TcpClient client) { if (client == null) throw new ArgumentNullException("client"); if (!client.Connected) throw new ArgumentNullException("client is not connected"); var iPEndPoint= client.Client.RemoteEndPoint as IPEndPoint; _ip = iPEndPoint.Address.ToString(); _port= iPEndPoint.Port; //_port = port; var modbusFactory = new ModbusFactory(); _client = client; _modbusMaster = modbusFactory.CreateMaster(_client); } public void Connect() { try { _client.Connect(_ip, _port); IsConnect = true; OnConnectChanged(true); } catch (Exception e) { OnConnectChanged(false); IsConnect = false; } } public byte SlaveId { get; set; } = 1; public async Task ConnectAsync() { try { if (_client.Connected) { return; } await _client.ConnectAsync(_ip, _port); OnConnectChanged(true); IsConnect = true; } catch (Exception e) { Console.WriteLine(e); OnConnectChanged(false); IsConnect = false; } } public async Task ReConnect() { if (_client != null) { _client.Dispose(); } try { _client = new TcpClient(); if (_client.Connected) { return true; } await _client.ConnectAsync(_ip, _port); var modbusFactory = new ModbusFactory(); _modbusMaster = modbusFactory.CreateMaster(_client); OnConnectChanged(true); IsConnect = true; } catch (Exception e) { Console.WriteLine(e); OnConnectChanged(false); IsConnect = false; } return IsConnect; } public ushort[] ReadBytes(ushort start, ushort length) { var byteData = _modbusMaster.ReadHoldingRegisters(SlaveId, start, length); return byteData; } /// /// 获取单个位状态 /// /// 从PLC里读出第几个字节 /// 第几位 /// public bool GetBool(ushort start, ushort index) { try { var byteData = _modbusMaster.ReadHoldingRegisters(SlaveId, start, 1); var num = byteData[0]; var bitGroup = new bool[16]; for (ushort i = 0; i < 16; i++) { bitGroup[i] = ((num >> i) & 1) == 1; } return bitGroup[index]; } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } public List> GetBoolList(IEnumerable addresses) { var boolList = new List>(); var byteData = _modbusMaster.ReadHoldingRegisters(SlaveId, 0, 50); foreach (var address in addresses) { var stringSplits = address.Split('.'); var byteIndex = ushort.Parse(stringSplits[0]); var byteIndex1 = byteIndex % 2 == 0 ? byteIndex / 2: byteIndex-1 / 2; var index = int.Parse(stringSplits[1]); var num = byteData[byteIndex1]; var bitGroup = new bool[16]; for (ushort i = 0; i < 16; i++) { bitGroup[i] = ((num >> i) & 1) == 1; } var addressValue = bitGroup[index]; boolList.Add(new KeyValuePair(address, addressValue)); } return boolList; } /// /// 获取单个位状态 /// /// 从PLC里读出第几个字节 /// 第几位 /// public async Task GetBoolAsync(ushort start, ushort index) { try { var byteData = await _modbusMaster.ReadHoldingRegistersAsync(SlaveId, start, 1); var num = byteData[0]; var tempBytes = BitConverter.GetBytes(num); var revertBytes = tempBytes.Reverse().ToArray(); var realValue = BitConverter.ToUInt16(revertBytes, 0); var bitGroup = new bool[16]; for (ushort i = 0; i < 16; i++) { bitGroup[i] = ((realValue >> i) & 1) == 1; } return bitGroup[index]; } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 写modbus位 /// /// /// /// public void WriteBool(ushort start, int index, bool flag) { try { var doCh = new bool[16]; var currentValue = GetShort(start); for (ushort i = 0; i < 16; i++) { doCh[i] = ((currentValue >> i) & 1) == 1; //获取PLC当前状态 } ushort outValue = 0; doCh[index] = flag; var front = new bool[8]; var back = new bool[8]; Array.Copy(doCh, 0, front, 0, 8); Array.Copy(doCh, 8, back, 0, 8); for (ushort i = 0; i < 16; i++) { outValue |= (ushort) (Convert.ToUInt16(doCh[i]) << i); } _modbusMaster.WriteMultipleRegisters(SlaveId, start, new[] {outValue}); } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } } /// /// 写modbus位 /// /// /// /// public async Task WriteBoolAsync(ushort start, int index, bool flag) { try { var doCh = new bool[16]; var currentValue = await GetShortAsync(start); for (ushort i = 0; i < 16; i++) { doCh[i] = ((currentValue >> i) & 1) == 1; //获取PLC当前状态 } ushort outValue = 0; doCh[index] = flag; var front = new bool[8]; var back = new bool[8]; Array.Copy(doCh, 0, front, 0, 8); Array.Copy(doCh, 8, back, 0, 8); for (ushort i = 0; i < 16; i++) { outValue |= (ushort) (Convert.ToUInt16(doCh[i]) << i); } var reverseValue = BitConverter.GetBytes(outValue); var outValue1 = BitConverter.ToUInt16(reverseValue, 0); await _modbusMaster.WriteMultipleRegistersAsync(SlaveId, start, new[] {outValue1}); } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } } /// /// 写modbus位 /// /// /// /// public void WriteByte(ushort start, int index, byte value) { try { var currentValue = GetShort(start); var bytes = BitConverter.GetBytes(currentValue); bytes[index] = value; var writeValue = BitConverter.ToUInt16(bytes, 0); _modbusMaster.WriteMultipleRegisters(SlaveId, start, new[] {writeValue}); } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } } /// /// 写modbus位 /// /// /// /// public async Task WriteByteAsync(ushort start, int index, byte value)//todo need to test { try { var currentValue = await GetShortAsync(start); var bytes = BitConverter.GetBytes(currentValue); bytes[index] = value; var writeValue = BitConverter.ToUInt16(bytes, 0); await _modbusMaster.WriteSingleRegisterAsync(SlaveId, start, writeValue); } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 获取浮点数值 /// /// 数据索引 /// public float GetFloat(ushort index) { try { var shortData = _modbusMaster.ReadHoldingRegisters(SlaveId, index, 2); var bytes1 = BitConverter.GetBytes(shortData[0]); var bytes2 = BitConverter.GetBytes(shortData[1]); var mergeBytes = bytes1.Concat(bytes2); return BitConverter.ToSingle(mergeBytes.ToArray(), 0); } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 获取浮点数值 /// /// 数据索引 /// public async Task GetFloatAsync(ushort index) { try { var shortData = await _modbusMaster.ReadHoldingRegistersAsync(SlaveId, index, 2); var bytes1 = BitConverter.GetBytes(shortData[0]); var bytes2 = BitConverter.GetBytes(shortData[1]); var mergeBytes = bytes1.Concat(bytes2); return BitConverter.ToSingle(mergeBytes.ToArray(), 0); } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 获取字 /// /// 数据索引 /// public ushort GetShort(ushort index) { try { var shortData = _modbusMaster.ReadHoldingRegisters(SlaveId, index, 1); var shortBytes = BitConverter.GetBytes(shortData[0]); var realBytes = shortBytes; var realValue = BitConverter.ToUInt16(realBytes, 0); return realValue; } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } } /// /// 获取字 /// /// 数据索引 /// public async Task GetShortAsync(ushort index) { try { var shortData = await _modbusMaster.ReadHoldingRegistersAsync(SlaveId, index, 1); var shortBytes = BitConverter.GetBytes(shortData[0]); var realValue = BitConverter.ToUInt16(shortBytes, 0); return realValue; } catch (IOException) { IsConnect = false; throw; } } /// /// 获取整型数值 /// /// 4字节整数 /// 数据索引 /// public int GetInteger(ushort index) { try { var shortData = _modbusMaster.ReadHoldingRegisters(SlaveId, index, 2); var bytes1 = BitConverter.GetBytes(shortData[0]); var bytes2 = BitConverter.GetBytes(shortData[1]); var mergeBytes = bytes1.Concat(bytes2); return BitConverter.ToInt32(mergeBytes.ToArray(), 0); } catch (IOException) { IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 异步获取整型数值 /// /// 4字节整数 /// 数据索引 /// public async Task GetIntegerAsync(ushort index) { try { var shortData = await _modbusMaster.ReadHoldingRegistersAsync(SlaveId, index, 2); var bytes1 = BitConverter.GetBytes(shortData[0]); var bytes2 = BitConverter.GetBytes(shortData[1]); var mergeBytes = bytes1.Concat(bytes2); return BitConverter.ToInt32(mergeBytes.ToArray(), 0); } catch (IOException) { IsConnect = false; OnConnectChanged(false); throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 读字节 /// /// 开始字索引 /// 第几个字节 /// public async Task GetByteAsync(ushort start, int index) { try { var shortData = await _modbusMaster.ReadHoldingRegistersAsync(SlaveId, start, 1); var bytes1 = BitConverter.GetBytes(shortData[0]).Reverse().ToArray(); return bytes1[index]; } catch (IOException) { IsConnect = false; OnConnectChanged(false); throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 读字节 /// /// 开始字索引 /// 第几个字节 /// public byte GetByte(ushort start, int index) { try { var shortData = _modbusMaster.ReadHoldingRegisters(SlaveId, start, 1); var bytes1 = BitConverter.GetBytes(shortData[0]).Reverse().ToArray(); return bytes1[index]; } catch (IOException) { OnConnectChanged(false); IsConnect = false; throw; } catch (Exception e) { Console.WriteLine(e); throw; } } /// /// 反转多字节的数据信息 /// /// 数据字节 /// 起始索引,默认值为0 /// 实际字节信息 protected byte[] ByteTransDataFormat2(byte[] value, int index = 0) { var buffer = new byte[2]; switch (DataFormat) { case DataFormat.ABCD: { buffer[0] = value[index + 1]; buffer[1] = value[index + 0]; break; } case DataFormat.BADC: { buffer[0] = value[index + 0]; buffer[1] = value[index + 1]; break; } case DataFormat.CDAB: { buffer[0] = value[index + 1]; buffer[1] = value[index + 0]; break; } case DataFormat.DCBA: { buffer[0] = value[index + 0]; buffer[1] = value[index + 1]; break; } } return buffer; } /// /// 反转多字节的数据信息 /// /// 数据字节 /// 起始索引,默认值为0 /// 实际字节信息 protected byte[] ByteTransDataFormat8(byte[] value, int index = 0) { byte[] buffer = new byte[8]; switch (DataFormat) { case DataFormat.ABCD: { buffer[0] = value[index + 7]; buffer[1] = value[index + 6]; buffer[2] = value[index + 5]; buffer[3] = value[index + 4]; buffer[4] = value[index + 3]; buffer[5] = value[index + 2]; buffer[6] = value[index + 1]; buffer[7] = value[index + 0]; break; } case DataFormat.BADC: { buffer[0] = value[index + 6]; buffer[1] = value[index + 7]; buffer[2] = value[index + 4]; buffer[3] = value[index + 5]; buffer[4] = value[index + 2]; buffer[5] = value[index + 3]; buffer[6] = value[index + 0]; buffer[7] = value[index + 1]; break; } case DataFormat.CDAB: { buffer[0] = value[index + 1]; buffer[1] = value[index + 0]; buffer[2] = value[index + 3]; buffer[3] = value[index + 2]; buffer[4] = value[index + 5]; buffer[5] = value[index + 4]; buffer[6] = value[index + 7]; buffer[7] = value[index + 6]; break; } case DataFormat.DCBA: { buffer[0] = value[index + 0]; buffer[1] = value[index + 1]; buffer[2] = value[index + 2]; buffer[3] = value[index + 3]; buffer[4] = value[index + 4]; buffer[5] = value[index + 5]; buffer[6] = value[index + 6]; buffer[7] = value[index + 7]; break; } } return buffer; } /// /// 反转多字节的数据信息 /// /// 数据字节 /// 起始索引,默认值为0 /// 实际字节信息 protected byte[] ByteTransDataFormat4(byte[] value, int index = 0) { var buffer = new byte[4]; switch (DataFormat) { case DataFormat.ABCD: { buffer[0] = value[index + 3]; buffer[1] = value[index + 2]; buffer[2] = value[index + 1]; buffer[3] = value[index + 0]; break; } case DataFormat.BADC: { buffer[0] = value[index + 2]; buffer[1] = value[index + 3]; buffer[2] = value[index + 0]; buffer[3] = value[index + 1]; break; } case DataFormat.CDAB: { buffer[0] = value[index + 1]; buffer[1] = value[index + 0]; buffer[2] = value[index + 3]; buffer[3] = value[index + 2]; break; } case DataFormat.DCBA: { buffer[0] = value[index + 0]; buffer[1] = value[index + 1]; buffer[2] = value[index + 2]; buffer[3] = value[index + 3]; break; } } return buffer; } public virtual byte[] TransByte(int[] values) { if (values == null) return null; byte[] buffer = new byte[values.Length * 4]; for (int i = 0; i < values.Length; i++) { ByteTransDataFormat4(BitConverter.GetBytes(values[i])).CopyTo(buffer, 4 * i); } return buffer; } public virtual byte[] TransByte(ushort[] values) { if (values == null) return null; byte[] buffer = new byte[values.Length * 2]; for (int i = 0; i < values.Length; i++) { BitConverter.GetBytes(values[i]).CopyTo(buffer, 2 * i); } return buffer; } public void WriteDouble(ushort start, double value) { var convertBytes = BitConverter.GetBytes(value); var writeValues = new ushort[2]; for (var i = 0; i < 4; i++) { var bytes = new[] { convertBytes[i * 2], convertBytes[i * 2 + 1] }; writeValues[i] = BitConverter.ToUInt16(bytes, 0); } _modbusMaster.WriteMultipleRegisters(SlaveId, start, writeValues); } public async Task WriteDoubleAsync(ushort start, double value) { var convertBytes = BitConverter.GetBytes(value); var writeValues = new ushort[4]; for (var i = 0; i < 4; i++) { var bytes = new[] { convertBytes[i * 2], convertBytes[i * 2 + 1] }; writeValues[i] = BitConverter.ToUInt16(bytes, 0); } await _modbusMaster.WriteMultipleRegistersAsync(SlaveId, start, writeValues); } public void WriteFloat(ushort start, float value) { var convertBytes = BitConverter.GetBytes(value); var writeValues = new ushort[2]; for (int i = 0; i < 4; i++) { var bytes = new[] { convertBytes[i * 2], convertBytes[i * 2 + 1] }; writeValues[i] = BitConverter.ToUInt16(bytes, 0); } _modbusMaster.WriteMultipleRegisters(SlaveId, start, writeValues); } public async Task WriteFloatAsync(ushort start, float value) { var convertBytes = BitConverter.GetBytes(value); var writeValues = new ushort[2]; for (var i = 0; i < 2; i++) { var bytes = new[] { convertBytes[i * 2], convertBytes[i * 2 + 1] }; writeValues[i] = BitConverter.ToUInt16(bytes, 0); } await _modbusMaster.WriteMultipleRegistersAsync(SlaveId, start, writeValues); } public void WriteInt32(ushort start, int value) { var convertBytes = BitConverter.GetBytes(value); var writeValues = new ushort[2]; for (int i = 0; i < 2; i++) { var bytes = new[] { convertBytes[i * 2], convertBytes[i * 2 + 1] }; writeValues[i] = BitConverter.ToUInt16(bytes, 0); } _modbusMaster.WriteMultipleRegisters(SlaveId, start, writeValues); } public async Task WriteInt32Async(ushort start, int value) { var convertBytes = BitConverter.GetBytes(value); var writeValues = new ushort[2]; for (var i = 0; i < 2; i++) { var bytes = new[] { convertBytes[i * 2], convertBytes[i * 2 + 1] }; writeValues[i] = BitConverter.ToUInt16(bytes, 0); } await _modbusMaster.WriteMultipleRegistersAsync(SlaveId, start, writeValues); } public ushort[] GetBytes(ushort start, ushort length) { var nums= _modbusMaster.ReadInputRegisters(1,start, length); return nums; } public Task GetBytesAsync(ushort start, ushort length) { return _modbusMaster.ReadInputRegistersAsync(SlaveId, start, length); } private void OnConnectChanged(bool state) { ConnectChanged?.Invoke(this, state); } } }