using System.Diagnostics; using InnovEnergy.Lib.Protocols.Modbus.Channels; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies; using InnovEnergy.Lib.Protocols.Modbus.Tcp; using InnovEnergy.Lib.Utils; namespace InnovEnergy.Lib.Protocols.Modbus.Clients; using UInt16s = IReadOnlyCollection; using Booleans = IReadOnlyCollection; public class ModbusTcpClient : ModbusClient { public const UInt16 DefaultPort = 502; private UInt16 _Id; [DebuggerStepThrough] private UInt16 NextId() => unchecked(++_Id); public ModbusTcpClient(Channel channel, Byte slaveId) : base(channel, slaveId) { } public override MbData ReadCoils(UInt16 readAddress, UInt16 nValues) { var id = NextId(); // TODO: check response id var cmd = new ReadCoilsCommandFrame(SlaveId, readAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); Channel.Write(frm.Data); var hData = Channel.Read(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var rxFrm = Channel .Read(rxHdr.FrameLength) .ToArray() // TODO: optimize .ToArray() ? .Apply(ReadCoilsResponseFrame.Parse) .Apply(cmd.VerifyResponse); return new MbData(rxFrm.Coils.RawData, readAddress, Endian); } public override MbData 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); Channel.Write(frm.Data); var hData = Channel.Read(MbapHeader.Size).ToArray(); // TODO: optimize .ToArray() ? var rxHdr = new MbapHeader(hData); var rxFrm = Channel .Read(rxHdr.FrameLength) .ToArray() // TODO: optimize .ToArray() ? .Apply(ReadDiscreteInputsResponseFrame.Parse) .Apply(cmd.VerifyResponse); return new MbData(rxFrm.Inputs.RawData, readAddress, Endian); } public override MbData 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); Channel.Write(frm.Data); var hData = Channel.Read(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var rxFrm = Channel .Read(rxHdr.FrameLength) .ToArray() .Apply(ReadInputRegistersResponseFrame.Parse) .Apply(cmd.VerifyResponse); return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); } public override MbData 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); Channel.Write(frm.Data); var hData = Channel.Read(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var rxFrm = Channel .Read(rxHdr.FrameLength) .ToArray() .Apply(ReadHoldingRegistersResponseFrame.Parse) .Apply(cmd.VerifyResponse); return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); } public override UInt16 WriteCoils(UInt16 writeAddress, Booleans 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); Channel.Write(frm.Data); var hData = Channel.Read(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var rxFrm = Channel .Read(rxHdr.FrameLength) .ToArray() .Apply(WriteCoilsResponseFrame.Parse) .Apply(cmd.VerifyResponse); return 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); Channel.Write(frm.Data); var hData = Channel.Read(MbapHeader.Size).ToArray(); var rxHdr = new MbapHeader(hData); var rxFrm = Channel .Read(rxHdr.FrameLength) .ToArray() .Apply(WriteRegistersResponseFrame.Parse) .Apply(cmd.VerifyResponse); return rxFrm.NbWritten; } public override MbData 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); Channel.Write(frm.Data); var hData = Enumerable.ToArray(Channel.Read(MbapHeader.Size)); var rxHdr = new MbapHeader(hData); var fData = Enumerable.ToArray(Channel.Read(rxHdr.FrameLength)); var rxFrm = fData .Apply(ReadWriteRegistersResponseFrame.Parse) .Apply(cmd.VerifyResponse); return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian); } }