174 lines
6.9 KiB
C#
174 lines
6.9 KiB
C#
using Nito.AsyncEx;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Modbus.Net.Siemens
|
|
{
|
|
/// <summary>
|
|
/// 西门子Tcp协议
|
|
/// </summary>
|
|
public class SiemensTcpProtocol : SiemensProtocol
|
|
{
|
|
private readonly string _ip;
|
|
private readonly ushort _maxCalled;
|
|
private readonly ushort _maxCalling;
|
|
private readonly ushort _maxPdu;
|
|
private readonly int _port;
|
|
private readonly ushort _taspSrc;
|
|
private readonly byte _tdpuSize;
|
|
private readonly ushort _tsapDst;
|
|
private int _connectTryCount;
|
|
private readonly AsyncLock _lock = new AsyncLock();
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="tdpuSize"></param>
|
|
/// <param name="tsapSrc"></param>
|
|
/// <param name="tsapDst"></param>
|
|
/// <param name="maxCalling"></param>
|
|
/// <param name="maxCalled"></param>
|
|
/// <param name="maxPdu"></param>
|
|
public SiemensTcpProtocol(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled,
|
|
ushort maxPdu)
|
|
: this(tdpuSize, tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ConfigurationReader.GetValueDirect("TCP:Siemens", "IP"))
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="tdpuSize"></param>
|
|
/// <param name="tsapSrc"></param>
|
|
/// <param name="tsapDst"></param>
|
|
/// <param name="maxCalling"></param>
|
|
/// <param name="maxCalled"></param>
|
|
/// <param name="maxPdu"></param>
|
|
/// <param name="ip">IP地址</param>
|
|
public SiemensTcpProtocol(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled,
|
|
ushort maxPdu, string ip)
|
|
: this(
|
|
tdpuSize, tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ip,
|
|
int.Parse(ConfigurationReader.GetValueDirect("TCP:Siemens", "SiemensPort")))
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="tdpuSize"></param>
|
|
/// <param name="tsapSrc"></param>
|
|
/// <param name="tsapDst"></param>
|
|
/// <param name="maxCalling"></param>
|
|
/// <param name="maxCalled"></param>
|
|
/// <param name="maxPdu"></param>
|
|
/// <param name="ip">IP地址</param>
|
|
/// <param name="port">端口</param>
|
|
public SiemensTcpProtocol(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled,
|
|
ushort maxPdu, string ip, int port) : base(0, 0)
|
|
{
|
|
_taspSrc = tsapSrc;
|
|
_tsapDst = tsapDst;
|
|
_maxCalling = maxCalling;
|
|
_maxCalled = maxCalled;
|
|
_maxPdu = maxPdu;
|
|
_tdpuSize = tdpuSize;
|
|
_ip = ip;
|
|
_port = port;
|
|
_connectTryCount = 0;
|
|
ProtocolLinker = new SiemensTcpProtocolLinker(_ip, _port);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发送数据并接收
|
|
/// </summary>
|
|
/// <param name="content">发送的数据</param>
|
|
/// <returns>返回的数据</returns>
|
|
public override PipeUnit SendReceive(params object[] content)
|
|
{
|
|
return AsyncHelper.RunSync(() => SendReceiveAsync(Endian, content));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发送数据并接收
|
|
/// </summary>
|
|
/// <param name="content">发送的数据</param>
|
|
/// <returns>返回的数据</returns>
|
|
public override async Task<PipeUnit> SendReceiveAsync(params object[] content)
|
|
{
|
|
if (ProtocolLinker == null || !ProtocolLinker.IsConnected)
|
|
await ConnectAsync();
|
|
return await base.SendReceiveAsync(Endian, content);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发送数据并接收
|
|
/// </summary>
|
|
/// <param name="unit">协议的核心</param>
|
|
/// <param name="content">协议的参数</param>
|
|
/// <returns>返回的数据</returns>
|
|
public override PipeUnit SendReceive(ProtocolUnit<byte[], byte[]> unit, IInputStruct content)
|
|
{
|
|
return AsyncHelper.RunSync(() => SendReceiveAsync(unit, content));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发送数据并接收
|
|
/// </summary>
|
|
/// <param name="unit">发送的数据</param>
|
|
/// <param name="content">协议的参数</param>
|
|
/// <returns>返回的数据</returns>
|
|
public override async Task<PipeUnit> SendReceiveAsync(ProtocolUnit<byte[], byte[]> unit, IInputStruct content)
|
|
{
|
|
if (ProtocolLinker != null && ProtocolLinker.IsConnected) return await base.SendReceiveAsync(unit, content);
|
|
if (_connectTryCount > 10) return null;
|
|
return
|
|
await
|
|
ConnectAsync()
|
|
.ContinueWith(answer => answer.Result ? base.SendReceiveAsync(unit, content) : null).Unwrap();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 强制发送数据并接收
|
|
/// </summary>
|
|
/// <param name="unit">发送的数据</param>
|
|
/// <param name="content">协议的参数</param>
|
|
/// <returns>返回的数据</returns>
|
|
private async Task<PipeUnit> ForceSendReceiveAsync(ProtocolUnit<byte[], byte[]> unit, IInputStruct content)
|
|
{
|
|
return await base.SendReceiveAsync(unit, content);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 连接设备
|
|
/// </summary>
|
|
/// <returns>设备是否连接成功</returns>
|
|
public override async Task<bool> ConnectAsync()
|
|
{
|
|
IOutputStruct outputStruct;
|
|
using (await _lock.LockAsync())
|
|
{
|
|
_connectTryCount++;
|
|
if (ProtocolLinker.IsConnected) return true;
|
|
if (!await ProtocolLinker.ConnectAsync()) return false;
|
|
_connectTryCount = 0;
|
|
var inputStruct = new CreateReferenceSiemensInputStruct(_tdpuSize, _taspSrc, _tsapDst);
|
|
outputStruct =
|
|
//先建立连接,然后建立设备的引用
|
|
(await (await
|
|
ForceSendReceiveAsync(this[typeof(CreateReferenceSiemensProtocol)], inputStruct))
|
|
.SendReceiveAsync(
|
|
this[typeof(EstablishAssociationSiemensProtocol)], answer =>
|
|
answer != null
|
|
? new EstablishAssociationSiemensInputStruct(0x0101, _maxCalling,
|
|
_maxCalled,
|
|
_maxPdu)
|
|
: null)).Unwrap<EstablishAssociationSiemensOutputStruct>();
|
|
if (outputStruct == null && ProtocolLinker.IsConnected)
|
|
{
|
|
ProtocolLinker.Disconnect();
|
|
}
|
|
}
|
|
return outputStruct != null;
|
|
}
|
|
}
|
|
} |