2023-02-16 12:57:06 +00:00
|
|
|
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;
|
2023-03-07 10:19:15 +00:00
|
|
|
using static InnovEnergy.Lib.Protocols.Modbus.Clients.Endianness;
|
2023-02-16 12:57:06 +00:00
|
|
|
|
|
|
|
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
|
|
|
|
|
|
|
using UInt16s = IReadOnlyList<UInt16>;
|
|
|
|
using Coils = IReadOnlyList<Boolean>;
|
|
|
|
|
|
|
|
public class ModbusTcpClient : ModbusClient
|
|
|
|
{
|
|
|
|
public const UInt16 DefaultPort = 502;
|
|
|
|
private UInt16 _Id;
|
|
|
|
|
|
|
|
[DebuggerStepThrough]
|
|
|
|
private UInt16 NextId() => unchecked(++_Id);
|
|
|
|
|
|
|
|
|
2023-03-07 10:19:15 +00:00
|
|
|
public ModbusTcpClient(ModbusConnection connection, Byte slaveId, Endianness endianness = LittleEndian32BitIntegers | LittleEndian32Floats) : base(connection, slaveId, endianness)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override IReadOnlyList<Boolean> 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());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|