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 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(string address, ushort len = 1, byte slaveAddress = 1) { if (address == null || tcpClient == null) return default(object); ushort startAddress = (ushort)GetAddress(address); CommandType commandType = CommandType.Coils; try { if (address.ToUpper().Contains("M")) { commandType = CommandType.Coils; return master.ReadCoils(slaveAddress, startAddress, len); } else if (address.ToUpper().Contains("VW")) { commandType = CommandType.HoldingRegisters; return master.ReadHoldingRegisters(slaveAddress, startAddress, len); } else if (address.ToUpper().Contains("I")) { commandType = CommandType.Inputs; return master.ReadInputs(slaveAddress, startAddress, len); } } catch (Exception ex) { MessageLog.GetInstance.ShowEx($"读取地址:【{address}:= {startAddress}】,读取类型:【{commandType.ToString()}】出错,{ex.ToString()}"); if (ex.InnerException is SocketException) { tcpClient = null; Connect(); } } return default(object); } public void Write(string address, T value, byte slaveAddress = 1) { if (address == null || tcpClient == null) return; ushort startAddress = (ushort)GetAddress(address); CommandType commandType = CommandType.Coils; try { if (address.ToUpper().Contains("M")) { commandType = CommandType.Coils; if (value is bool boolValue) master.WriteSingleCoil(slaveAddress, startAddress, boolValue); else if (value is bool[] boolsValue) master.WriteMultipleCoils(slaveAddress, startAddress, boolsValue); } else if (address.ToUpper().Contains("VW")) { commandType = CommandType.HoldingRegisters; if (value is ushort ushortValue) master.WriteSingleRegister(slaveAddress, startAddress, ushortValue); else if (value 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); } } } else if (address.ToUpper().Contains("I")) { commandType = CommandType.Inputs; } } catch (Exception ex) { MessageLog.GetInstance.ShowEx($"读写入地址:【{address}:= {startAddress}】,写入类型:【{commandType.ToString()}】出错,{ex.ToString()}"); if (ex.InnerException is SocketException) { tcpClient = null; Connect(); } } } //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 CommandType { /// /// 线圈操作 /// Coils, /// /// 输入线圈操作 /// Inputs, /// /// 保持寄存器操作 /// HoldingRegisters, /// /// 输入寄存器操作 /// InputRegisters, } }