using BPASmartClient.Message; using NModbus; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace BPASmartClient.Modbus { public class ModbusTcp { //private volatile static ModbusTcp _Instance; //public static ModbusTcp GetInstance => _Instance ?? (_Instance = new ModbusTcp()); //private ModbusTcp() { } private ModbusFactory modbusFactory; private IModbusMaster master; private TcpClient tcpClient; private string IPAdress; private int Port; //public Action ConnectOk { get; set; } /// /// 判断是否连接成功 /// public bool Connected => tcpClient == null ? false : tcpClient.Connected; /// /// ModbusTcp 连接设备 /// /// ip 地址 /// 端口号,默认502 public void ModbusTcpConnect(string ip, int port = 502) { MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接中。。。。"); IPAdress = ip; Port = port; modbusFactory = new ModbusFactory(); Connect(); master.Transport.ReadTimeout = 2000;//读取超时时间 master.Transport.WriteTimeout = 2000;//写入超时时间 master.Transport.Retries = 10;//重试次数 MessageLog.GetInstance.Show($"设备【{ip}:{port}】连接成功"); } private void Connect() { bool ErrorFlag = false; while (!Connected) { try { tcpClient = new TcpClient(IPAdress, Port); master = modbusFactory.CreateMaster(tcpClient); } catch (Exception ex) { if (!ErrorFlag) { MessageLog.GetInstance.ShowEx($"ModbusTcp 连接失败,IP = {IPAdress},Port = {Port}"); MessageLog.GetInstance.ShowEx(ex.ToString()); ErrorFlag = true; } Thread.Sleep(3000); } } MessageLog.GetInstance.Show("ModbusTcp 连接成功!"); } /// /// 获取 M 区 和 VW 区的Modbus的地址 /// /// /// public int GetAddress(string address) { if (address == null) return -1; if (address.Length > 0) { if (address.ToUpper().Contains("M") && address.Length >= 4) { var res = address.Substring(1).Split('.'); if (res != null && res.Length == 2) { if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress)) { if (ExitAddress >= 0 && ExitAddress <= 7) { return (firstAddress * 8) + 320 + ExitAddress; } } } } else if (address.ToUpper().Contains("VW") && address.Length >= 3) { var res = address.Substring(2); if (res != null && int.TryParse(res, out int tempAddress)) { return (tempAddress / 2) + 100; } } } return -1; } public int GetBoolAddress(string address) { if (address != null && address.Length >= 4) { var res = address.Substring(1).Split('.'); if (res != null && res.Length == 2) { if (int.TryParse(res[0], out int firstAddress) && int.TryParse(res[1], out int ExitAddress)) { if (ExitAddress >= 0 && ExitAddress <= 7) { return (firstAddress * 8) + 320 + ExitAddress; } } } } return -1; } public int GetWordAddress(string address) { if (address != null && address.Length > 3) { var res = address.Substring(2); if (res != null && int.TryParse(res, out int tempAddress)) { return (tempAddress / 2) + 100; } } return -1; } public void Readbool(ushort startAddress, ushort len, Action action) { object result; result = Read(startAddress, CommandType.Coils, len); if (result != null) { if (result is bool[] bools) { if (bools.Length == len) { action(bools); } } else if (result is bool bl) { List boolLists = new List(); boolLists.Add(bl); action(boolLists.ToArray()); } } } public object Read(ushort startAddress, CommandType readType, ushort num = 1, byte slaveAddress = 1) { object result = new object(); if (tcpClient == null) return result; if (num <= 0) return result; try { switch (readType) { case CommandType.Coils: result = master.ReadCoils(slaveAddress, startAddress, num); break; case CommandType.Inputs: result = master.ReadInputs(slaveAddress, startAddress, num); break; case CommandType.HoldingRegisters: result = master.ReadHoldingRegisters(slaveAddress, startAddress, num); break; case CommandType.InputRegisters: result = master.ReadInputRegisters(slaveAddress, startAddress, num); break; default: break; } if (result == null) return new object(); if (result is bool[] bools) { if (bools.Length == 1) return bools[0]; else return bools; } if (result is ushort[] ushorts) { if (ushorts.Length == 1) return ushorts[0]; else return ushorts; } } catch (Exception ex) { MessageLog.GetInstance.ShowEx($"读取地址:【{startAddress}】,读取类型:【{readType}】出错,{ex.ToString()}"); if (ex.InnerException is SocketException) { tcpClient = null; Connect(); } } return result; } public bool Write(ushort startAddress, CommandType writeType, object InputValue, byte slaveAddress = 1) { bool result = false; if (tcpClient == null) return result; if (!(InputValue is bool || InputValue is bool[] || InputValue is ushort || InputValue is ushort[])) return result; try { switch (writeType) { case CommandType.Coils: if (InputValue is bool boolValue) master.WriteSingleCoil(slaveAddress, startAddress, boolValue); if (InputValue is bool[] boolsValue) master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue); break; case CommandType.HoldingRegisters: if (InputValue is ushort ushortValue) master.WriteSingleRegister(slaveAddress, startAddress, ushortValue); if (InputValue is ushort[] ushortsValue) { int len = 100; if (ushortsValue.Length > len) { List ushortLists = new List(); for (int i = 0; i < ushortsValue.Length / len; i++) { ushortLists.Add(ushortsValue.Skip(0).Take(len).ToArray()); } int y = ushortsValue.Length % len; if (y > 0) { ushortLists.Add(ushortsValue.Skip(ushortsValue.Length - y).Take(y).ToArray()); } foreach (var item in ushortLists) { master.WriteMultipleRegisters(slaveAddress, startAddress, item); startAddress += (ushort)item.Length; } } else { master.WriteMultipleRegisters(slaveAddress, startAddress, ushortsValue); } } break; default: break; } } catch (Exception ex) { MessageLog.GetInstance.ShowEx(ex.ToString()); if (ex.InnerException is SocketException) { tcpClient = null; Connect(); } return false; } return true; } #region 批量数据读取 /// /// 读取多个线圈 /// /// /// /// /// public bool[] ReadCoils(ushort startAddress, ushort num, byte slaveAddress = 1) { return master.ReadCoils(slaveAddress, startAddress, num); } /// /// 读取多个输入线圈 /// /// /// /// /// public bool[] ReadInputs(ushort startAddress, ushort num, byte slaveAddress = 1) { return master.ReadInputs(slaveAddress, startAddress, num); } /// /// 读取多个保持寄存器 /// /// /// /// /// public ushort[] ReadHoldingRegisters(ushort startAddress, ushort num, byte slaveAddress = 1) { return master.ReadHoldingRegisters(slaveAddress, startAddress, num); } /// /// 读取多个输入寄存器 /// /// /// /// /// public ushort[] ReadInputRegisters(ushort startAddress, ushort num, byte slaveAddress = 1) { return master.ReadInputRegisters(slaveAddress, startAddress, num); } #endregion #region 批量数据写入 /// /// 写入多个线圈 /// /// /// /// public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveAddress = 1) { master.WriteMultipleCoils(slaveAddress, startAddress, value); } /// /// 写入多个寄存器 /// /// /// /// public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveAddress = 1) { master.WriteMultipleRegisters(slaveAddress, startAddress, value); } #endregion #region 单个数据读取 /// /// 读取单个线圈 /// /// /// /// public bool ReadCoils(ushort startAddress, byte slaveAddress = 1) { var result = master.ReadCoils(slaveAddress, startAddress, 1); if (result == null) return false; if (result.Length == 1) return result[0]; return false; //return master.ReadCoils(slaveAddress, startAddress, 1)[0]; } /// /// 读取单个输入线圈 /// /// /// /// public bool ReadInputs(ushort startAddress, byte slaveAddress = 1) { var result = master.ReadInputs(slaveAddress, startAddress, 1); if (result == null) return false; if (result.Length == 1) return result[0]; return false; //return master.ReadInputs(slaveAddress, startAddress, 1)[0]; } /// /// 读取单个保持寄存器 /// /// /// /// public ushort ReadHoldingRegisters(ushort startAddress, byte slaveAddress = 1) { if (tcpClient == null) return 0; ushort[] result = null; try { result = master.ReadHoldingRegisters(slaveAddress, startAddress, 1); } catch (Exception ex) { MessageLog.GetInstance.Show(ex.ToString()); tcpClient = null; Connect(); } if (result == null) return 0; if (result.Length == 1) return result[0]; return 0; //return master.ReadHoldingRegisters(slaveAddress, startAddress, 1)[0]; } /// /// 读取单个输入寄存器 /// /// /// /// public ushort ReadInputRegisters(ushort startAddress, byte slaveAddress = 1) { var result = master.ReadInputRegisters(slaveAddress, startAddress, 1); if (result == null) return 0; if (result.Length == 1) return result[0]; return 0; //return master.ReadInputRegisters(slaveAddress, startAddress, 1)[0]; } #endregion #region 单个数据写入 /// /// 写入单个线圈 /// /// /// /// public void WriteSingleCoil(ushort startAddress, bool value, byte slaveAddress = 1) { master.WriteSingleCoil(slaveAddress, startAddress, value); } /// /// 写入单个寄存器 /// /// /// /// public void WriteSingleRegister(ushort startAddress, ushort value, byte slaveAddress = 1) { master.WriteSingleRegister(slaveAddress, startAddress, value); } #endregion } public enum ReadType { /// /// 读线圈 /// Coils, /// /// 读输入线圈 /// Inputs, /// /// 读保持寄存器 /// HoldingRegisters, /// /// 读输入寄存器 /// InputRegisters, } public enum WriteType { /// /// 写线圈 /// Coils, /// /// 写保持寄存器 /// HoldingRegisters, } public enum CommandType { /// /// 线圈操作 /// Coils, /// /// 输入线圈操作 /// Inputs, /// /// 保持寄存器操作 /// HoldingRegisters, /// /// 输入寄存器操作 /// InputRegisters, } }