using NModbus; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace PLCControl.ModBus { public class Control : IPLCControl { private object locker = new object(); private System.Net.Sockets.TcpClient? tcpClient; private IModbusMaster? modbus; [AllowNull] public Action ConnectionChanged { get; set; } public bool IsConnected => tcpClient == null ? false : tcpClient.Connected; [AllowNull] public string IPAddress { get; set; } = "127.0.0.1"; public int Port { get; set; } = 502; public byte SlaveID { get; set; } = 1; private bool _isConnected; private void InvokeConnectionChanged(bool isConnected) { lock (locker) { if (_isConnected == isConnected) return; ConnectionChanged?.Invoke(isConnected); _isConnected = isConnected; } } public bool Connect() { try { var modbusFactory = new NModbus.ModbusFactory(); tcpClient = new System.Net.Sockets.TcpClient(); var result = tcpClient.ConnectAsync(IPAddress, Port).Wait(500); if (!result) return false; modbus = modbusFactory.CreateMaster(tcpClient); InvokeConnectionChanged(true); return true; } catch (Exception ex) { return false; } } public void Disconnect() { try { tcpClient?.Close(); InvokeConnectionChanged(false); } catch (Exception ex) { } } public bool ReadBit(ushort address, byte bitindex) { var result = Read(address, 2)[0]; return (result & (1 << bitindex)) != 0; } private ushort[] Read(ushort startaddr, byte addrnum) { try { if (modbus == null) return new ushort[addrnum / 2]; return modbus.ReadHoldingRegisters(SlaveID, (ushort)(startaddr +(addrnum>>2) - 1), (ushort)(addrnum >> 1)); } catch { Disconnect(); } return new ushort[addrnum / 2]; } public void ReadDatas(ushort startAddress, ref T value, byte bytecount) where T : unmanaged { if (modbus == null) return; try { var result = modbus.ReadHoldingRegisters(SlaveID, (ushort)(startAddress + (bytecount >>2) -1), (ushort)(bytecount >> 1)).Reverse().ToArray(); Unsafe.CopyBlock(ref Unsafe.As(ref value), ref Unsafe.As(ref result[0]), (uint)bytecount); } catch { Disconnect(); } } public void WriteDatas(ushort address,ref T data,byte bytecount) where T: unmanaged { if (modbus == null) return; try { ushort[] datas = new ushort[bytecount / 2]; Unsafe.CopyBlock(ref Unsafe.As(ref datas[0]), ref Unsafe.As(ref data), (uint)datas.Length * 2); modbus.WriteMultipleRegisters(SlaveID, (ushort)(address + (bytecount >>1) -1 - 1), datas); } catch { Disconnect(); } } public short ReadInt16(ushort address) { return Unsafe.As(ref Read(address, 2)[0]); } public void WriteBit(ushort address, byte bitindex, bool value) { var result = Read(address, 2)[0]; result = (ushort)(value ? result | (1 << bitindex) : result & ~(1 << bitindex)); WriteInt16(address, Unsafe.As(ref result)); } public void WriteInt16(ushort address, short value) { if (modbus == null) return; try { modbus.WriteSingleRegister(SlaveID, (ushort)(address - 1), Unsafe.As(ref value)); } catch { Disconnect(); } } } }