2023-02-16 12:57:06 +00:00
|
|
|
using System.Diagnostics;
|
2023-05-04 07:32:35 +00:00
|
|
|
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
|
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors;
|
2023-02-16 12:57:06 +00:00
|
|
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands;
|
|
|
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies;
|
|
|
|
using InnovEnergy.Lib.Protocols.Modbus.Tcp;
|
2023-04-20 13:03:13 +00:00
|
|
|
using InnovEnergy.Lib.Utils;
|
2023-04-04 12:51:06 +00:00
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
|
|
|
|
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
using UInt16s = IReadOnlyCollection<UInt16>;
|
|
|
|
using Booleans = IReadOnlyCollection<Boolean>;
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2024-06-07 08:36:15 +00:00
|
|
|
/*public class ModbusTcpClient : ModbusClient
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
public const UInt16 DefaultPort = 502;
|
|
|
|
private UInt16 _Id;
|
|
|
|
|
|
|
|
[DebuggerStepThrough]
|
|
|
|
private UInt16 NextId() => unchecked(++_Id);
|
|
|
|
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public ModbusTcpClient(Channel channel, Byte slaveId) : base(channel, slaveId)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public override MbData ReadCoils(UInt16 readAddress, UInt16 nValues)
|
2023-04-20 13:03:13 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-04-20 13:03:13 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Channel.Read(MbapHeader.Size).ToArray();
|
2023-04-20 13:03:13 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray() // TODO: optimize .ToArray() ?
|
|
|
|
.Apply(ReadCoilsResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
|
|
|
|
|
|
|
return new MbData(rxFrm.Coils.RawData, readAddress, Endian);
|
2023-04-20 13:03:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public override MbData ReadDiscreteInputs(UInt16 readAddress, UInt16 nValues)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
var id = NextId(); // TODO: check response id
|
|
|
|
|
2023-04-04 12:51:06 +00:00
|
|
|
var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, readAddress, nValues);
|
2023-02-16 12:57:06 +00:00
|
|
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
|
|
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Channel.Read(MbapHeader.Size).ToArray(); // TODO: optimize .ToArray() ?
|
2023-02-16 12:57:06 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray() // TODO: optimize .ToArray() ?
|
|
|
|
.Apply(ReadDiscreteInputsResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
|
|
|
|
|
|
|
return new MbData(rxFrm.Inputs.RawData, readAddress, Endian);
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public override MbData ReadInputRegisters(UInt16 readAddress, UInt16 nValues)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
var id = NextId(); // TODO: check response id
|
2023-03-10 12:57:39 +00:00
|
|
|
|
2023-04-04 12:51:06 +00:00
|
|
|
var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues);
|
2023-02-16 12:57:06 +00:00
|
|
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
|
|
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Channel.Read(MbapHeader.Size).ToArray();
|
2023-02-16 12:57:06 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray()
|
|
|
|
.Apply(ReadInputRegistersResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian);
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public override MbData ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
var id = NextId(); // TODO: check response id
|
2023-05-04 07:32:35 +00:00
|
|
|
|
2023-04-04 12:51:06 +00:00
|
|
|
var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues);
|
2023-02-16 12:57:06 +00:00
|
|
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
|
|
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Channel.Read(MbapHeader.Size).ToArray();
|
2023-02-16 12:57:06 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray()
|
|
|
|
.Apply(ReadHoldingRegistersResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian);
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public override UInt16 WriteCoils(UInt16 writeAddress, Booleans coils)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
2023-04-20 13:03:13 +00:00
|
|
|
var id = NextId(); // TODO: check response id
|
2023-04-04 12:51:06 +00:00
|
|
|
var cmd = new WriteCoilsCommandFrame(SlaveId, writeAddress, coils);
|
2023-02-16 12:57:06 +00:00
|
|
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
|
|
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Channel.Read(MbapHeader.Size).ToArray();
|
2023-02-16 12:57:06 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray()
|
|
|
|
.Apply(WriteCoilsResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
return rxFrm.NbWritten;
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
2023-04-20 13:03:13 +00:00
|
|
|
|
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values)
|
|
|
|
{
|
|
|
|
var id = NextId(); // TODO: check response id
|
2023-04-04 12:51:06 +00:00
|
|
|
var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values);
|
2023-02-16 12:57:06 +00:00
|
|
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
|
|
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Channel.Read(MbapHeader.Size).ToArray();
|
2023-02-16 12:57:06 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray()
|
|
|
|
.Apply(WriteRegistersResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
return rxFrm.NbWritten;
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public override MbData ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
var id = NextId(); // TODO: check response id
|
|
|
|
|
2023-03-10 12:57:39 +00:00
|
|
|
var cmd = new ReadWriteRegistersCommandFrame(SlaveId,
|
2023-04-04 12:51:06 +00:00
|
|
|
readAddress,
|
2023-03-10 12:57:39 +00:00
|
|
|
nbToRead,
|
2023-04-04 12:51:06 +00:00
|
|
|
writeAddress,
|
2023-03-10 12:57:39 +00:00
|
|
|
registersToWrite);
|
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
var hdr = new MbapHeader(id, cmd.Data.Count);
|
|
|
|
var frm = new ModbusTcpFrame(hdr, cmd);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
Channel.Write(frm.Data);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var hData = Enumerable.ToArray(Channel.Read(MbapHeader.Size));
|
2023-02-16 12:57:06 +00:00
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
var fData = Enumerable.ToArray(Channel.Read(rxHdr.FrameLength));
|
|
|
|
var rxFrm = fData
|
|
|
|
.Apply(ReadWriteRegistersResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
return new MbData(rxFrm.RegistersRead.RawData, readAddress, Endian);
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
2024-06-07 08:36:15 +00:00
|
|
|
}*/
|
|
|
|
|
|
|
|
public class ModbusTcpClient : ModbusClient
|
|
|
|
{
|
|
|
|
public const ushort DefaultPort = 502;
|
|
|
|
private ushort _Id;
|
|
|
|
public TcpChannel Channel { get; }
|
|
|
|
|
|
|
|
public ModbusTcpClient(TcpChannel channel, byte slaveId) : base(channel, slaveId)
|
|
|
|
{
|
|
|
|
Channel = channel;
|
|
|
|
Channel.Connect();
|
|
|
|
}
|
|
|
|
|
|
|
|
private ushort NextId() => unchecked(++_Id);
|
|
|
|
|
|
|
|
public override MbData ReadCoils(ushort readAddress, ushort 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()
|
|
|
|
.Apply(ReadCoilsResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
|
|
|
|
|
|
|
return new MbData(rxFrm.Coils.RawData, readAddress, Endian);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override MbData ReadDiscreteInputs(ushort readAddress, ushort 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();
|
|
|
|
var rxHdr = new MbapHeader(hData);
|
|
|
|
|
|
|
|
var rxFrm = Channel
|
|
|
|
.Read(rxHdr.FrameLength)
|
|
|
|
.ToArray()
|
|
|
|
.Apply(ReadDiscreteInputsResponseFrame.Parse)
|
|
|
|
.Apply(cmd.VerifyResponse);
|
|
|
|
|
|
|
|
return new MbData(rxFrm.Inputs.RawData, readAddress, Endian);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override MbData ReadInputRegisters(ushort readAddress, ushort 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(ushort readAddress, ushort 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 ushort WriteCoils(ushort 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 ushort WriteRegisters(ushort 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(ushort readAddress, ushort nbToRead, ushort 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);
|
|
|
|
}
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|