using JSMachine.WMS.Infrastructure.Helper; using NModbus; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace JSMachine.WMS.PLC { /// /// Modbus TCP 通信引擎基类,封装 PLC 连接、重连以及寄存器/线圈读写操作。 /// public abstract class ModbusEngineBase : IModbusEngine { private IModbusMaster _modbusMaster { get; set; } private string _ip { get; set; } private int _port { get; set; } /// /// 保存 PLC 网络端点,实际连接在首次通信或显式连接时建立。 /// /// PLC IP 地址。 /// PLC TCP 端口。 /// 当前通信引擎实例。 public virtual IModbusEngine Init(string ip, int port) { _ip = ip; _port = port; return this; } private object _locker = new(); private TcpClient _tcpClient = new(); /// /// 建立 PLC TCP 连接;连接过程加锁以避免并发重连,超时时间为 2 秒。 /// /// 当前通信引擎实例。 public IModbusEngine Connet() { lock (_locker) { if (!_tcpClient.Connected) { try { _tcpClient = new(); IAsyncResult asyncResult = _tcpClient.BeginConnect(IPAddress.Parse(_ip), _port, null, null); if (asyncResult.AsyncWaitHandle.WaitOne(2000)) { _tcpClient.EndConnect(asyncResult); ModbusFactory factory = new(); _modbusMaster = factory.CreateMaster(_tcpClient); } else { _tcpClient.Close(); LogHelper.Error($"连接 PLC {_ip}:{_port} 超时"); } } catch (Exception ex) { _tcpClient.Close(); _modbusMaster = null; } } } return this; } /// /// 判断 Modbus 主站是否已初始化。 /// /// 主站对象不为空时返回 。 public bool IsConneted() { return !(_modbusMaster == null); } /// /// 批量读取线圈值 /// /// /// /// /// public bool[] ReadCoils(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { if (_modbusMaster == null) { this.Connet(); return null; } try { return _modbusMaster.ReadCoils(slaveAddress, startAddress, numberOfPoints); } catch (Exception ex) { LogHelper.Error($"批量读取PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return null; } } /// /// 批量读取线圈值(异步) /// /// /// /// /// public async Task ReadCoilsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { if (_modbusMaster == null) { this.Connet(); return null; } try { return await _modbusMaster.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints); } catch (Exception ex) { LogHelper.Error($"批量读取PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return null; } } /// /// 无符号读取 /// /// /// /// /// public ushort[] ReadUshorts(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { if (_modbusMaster == null) { this.Connet(); return null; } try { ushort[] data = _modbusMaster.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints); return data; } catch (Exception ex) { LogHelper.Error($"无符号读取PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return null; } } /// /// 无符号读取(异步) /// /// /// /// /// public async Task ReadUshortsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { if (_modbusMaster == null) { this.Connet(); return null; } try { ushort[] data = await _modbusMaster.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints); return data; } catch (Exception ex) { LogHelper.Error($"无符号读取PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return null; } } /// /// 有符号读取 /// /// /// /// /// public short[] ReadShorts(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { try { ushort[] data = ReadUshorts(slaveAddress, startAddress, numberOfPoints); if (data == null) return null; //计算补码 short[] rtn = data.Select(p => BitConverter.ToInt16(BitConverter.GetBytes(p))).ToArray(); return rtn; } catch (Exception ex) { LogHelper.Error($"有符号读取PLC信息失败,错误消息:{ex.Message}"); return null; } } /// /// 有符号读取(异步) /// /// /// /// /// public async Task ReadShortsAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { try { ushort[] data = await ReadUshortsAsync(slaveAddress, startAddress, numberOfPoints); if (data == null) return null; //计算补码 short[] rtn = data.Select(p => BitConverter.ToInt16(BitConverter.GetBytes(p))).ToArray(); return rtn; } catch (Exception ex) { LogHelper.Error($"有符号读取PLC信息失败,错误消息:{ex.Message}"); return null; } } /// /// 写单个无符号值 /// /// /// /// /// public bool WriteUshortOne(byte slaveAddress, ushort startAddress, ushort data) { if (_modbusMaster == null) { this.Connet(); return false; } try { _modbusMaster.WriteSingleRegister(slaveAddress, startAddress, data); return true; } catch (Exception ex) { LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写单个无符号值(异步) /// /// /// /// /// public async Task WriteUshortOneAsync(byte slaveAddress, ushort startAddress, ushort data) { if (_modbusMaster == null) { this.Connet(); return false; } try { await _modbusMaster.WriteSingleRegisterAsync(slaveAddress, startAddress, data); return true; } catch (Exception ex) { LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写单个有符号值 /// /// /// /// /// public bool WriteShortOne(byte slaveAddress, ushort startAddress, short data) { if (_modbusMaster == null) { this.Connet(); return false; } try { ushort writeData = BitConverter.ToUInt16(new ReadOnlySpan(BitConverter.GetBytes(data))); _modbusMaster.WriteSingleRegister(slaveAddress, startAddress, writeData); return true; } catch (Exception ex) { LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写单个线圈值 /// /// /// /// /// public bool WriteCoilOne(byte slaveAddress, ushort startAddress, bool data) { if (_modbusMaster == null) { this.Connet(); return false; } try { _modbusMaster.WriteSingleCoil(slaveAddress, startAddress, data); return true; } catch (Exception ex) { LogHelper.Error($"写单个线圈值失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写单个线圈值 /// /// /// /// /// public async Task WriteCoilOneAsync(byte slaveAddress, ushort startAddress, bool data) { if (_modbusMaster == null) { this.Connet(); return false; } try { await _modbusMaster.WriteSingleCoilAsync(slaveAddress, startAddress, data); return true; } catch (Exception ex) { LogHelper.Error($"写单个线圈值失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写单个有符号值(异步) /// /// /// /// /// public async Task WriteShortOneAsync(byte slaveAddress, ushort startAddress, short data) { if (_modbusMaster == null) { this.Connet(); return false; } try { ushort writeData = BitConverter.ToUInt16(new ReadOnlySpan(BitConverter.GetBytes(data))); await _modbusMaster.WriteSingleRegisterAsync(slaveAddress, startAddress, writeData); return true; } catch (Exception ex) { LogHelper.Error($"写单个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写多个无符号值 /// /// /// /// /// public bool WriteUshortsMany(byte slaveAddress, ushort startAddress, ushort[] data) { if (_modbusMaster == null) { this.Connet(); return false; } try { _modbusMaster.WriteMultipleRegisters(slaveAddress, startAddress, data); return true; } catch (Exception ex) { LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写多个无符号值(异步) /// /// /// /// /// public async Task WriteUshortsManyAsync(byte slaveAddress, ushort startAddress, ushort[] data) { if (_modbusMaster == null) { this.Connet(); return false; } try { await _modbusMaster.WriteMultipleRegistersAsync(slaveAddress, startAddress, data); return true; } catch (Exception ex) { LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写多个有符号值 /// /// /// /// /// public bool WriteShortsMany(byte slaveAddress, ushort startAddress, short[] data) { if (_modbusMaster == null) { this.Connet(); return false; } if (data == null || data.Length == 0) { return false; } try { ushort[] writeData = data.Select(p => BitConverter.ToUInt16(new ReadOnlySpan(BitConverter.GetBytes(p)))).ToArray(); _modbusMaster.WriteMultipleRegisters(slaveAddress, startAddress, writeData); return true; } catch (Exception ex) { LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } /// /// 写多个有符号值(异步) /// /// /// /// /// public async Task WriteShortsManyAsync(byte slaveAddress, ushort startAddress, short[] data) { if (_modbusMaster == null) { this.Connet(); return false; } if (data == null || data.Length == 0) { return false; } try { ushort[] writeData = data.Select(p => BitConverter.ToUInt16(new ReadOnlySpan(BitConverter.GetBytes(p)))).ToArray(); await _modbusMaster.WriteMultipleRegistersAsync(slaveAddress, startAddress, writeData); return true; } catch (Exception ex) { LogHelper.Error($"写多个PLC信息失败,错误消息:{ex.Message}"); this.Connet(); return false; } } } }