using System.Diagnostics; using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Conversions; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies; using InnovEnergy.Lib.Protocols.Modbus.Tcp; using static InnovEnergy.Lib.Protocols.Modbus.Clients.Endianness; namespace InnovEnergy.Lib.Protocols.Modbus.Clients; using UInt16s = IReadOnlyList; using Coils = IReadOnlyList; public class ModbusTcpClient : ModbusClient { public const UInt16 DefaultPort = 502; private UInt16 _Id; [DebuggerStepThrough] private UInt16 NextId() => unchecked(++_Id); public ModbusTcpClient(ModbusConnection connection, Byte slaveId, Endianness endianness = LittleEndian32BitIntegers | LittleEndian32Floats) : base(connection, slaveId, endianness) { } public override IReadOnlyList ReadDiscreteInputs(UInt16 readAddress, UInt16 nValues) { var id = NextId(); // TODO: check response id var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Connection.Transmit(frm.Data); var hData = Connection.Receive(MbapHeader.Size).ToArray(); // TODO: optimize .ToArray() ? var rxHdr = new MbapHeader(hData); var fData = Connection.Receive(rxHdr.FrameLength).ToArray(); // TODO: optimize .ToArray() ? var rxFrm = ReadDiscreteInputResponseFrame.Parse(fData); return cmd.VerifyResponse(rxFrm).Inputs; } public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues) { var id = NextId(); // TODO: check response id var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Connection.Transmit(frm.Data); var hData = Connection.Receive(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var fData = Connection.Receive(rxHdr.FrameLength).ToArray(); var rxFrm = ReadInputRegistersResponseFrame.Parse(fData); var verified = cmd.VerifyResponse(rxFrm); return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); } public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues) { var id = NextId(); // TODO: check response id var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Connection.Transmit(frm.Data); var hData = Connection.Receive(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var fData = Connection.Receive(rxHdr.FrameLength).ToArray(); var rxFrm = ReadHoldingRegistersResponseFrame.Parse(fData); var verified = cmd.VerifyResponse(rxFrm); return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); } public override UInt16 WriteMultipleCoils(UInt16 writeAddress, Coils coils) { var id = NextId(); // TODO: check response id var cmd = new WriteCoilsCommandFrame(SlaveId, writeAddress, coils); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Connection.Transmit(frm.Data); var hData = Connection.Receive(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var fData = Connection.Receive(rxHdr.FrameLength).ToArray(); var rxFrm = WriteCoilsResponseFrame.Parse(fData); return cmd.VerifyResponse(rxFrm).NbWritten; } public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values) { var id = NextId(); // TODO: check response id var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Connection.Transmit(frm.Data); var hData = Connection.Receive(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var fData = Connection.Receive(rxHdr.FrameLength).ToArray(); var rxFrm = WriteRegistersResponseFrame.Parse(fData); var verified = cmd.VerifyResponse(rxFrm); return verified.NbWritten; } public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite) { var id = NextId(); // TODO: check response id var cmd = new ReadWriteRegistersCommandFrame(SlaveId, readAddress, nbToRead, writeAddress, registersToWrite); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Connection.Transmit(frm.Data); var hData = Connection.Receive(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var fData = Connection.Receive(rxHdr.FrameLength).ToArray(); var rxFrm = ReadWriteRegistersResponseFrame.Parse(fData); var verified = cmd.VerifyResponse(rxFrm); return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); } }