175 lines
5.7 KiB
C#
175 lines
5.7 KiB
C#
using S7.Net;
|
|
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DeviceCommand.Base
|
|
{
|
|
public class S7Device : IS7Device
|
|
{
|
|
public string IPAddress { get; private set; } = "127.0.0.1";
|
|
public CpuType CpuType { get; private set; } = CpuType.S71200;
|
|
public short Rack { get; private set; } = 0;
|
|
public short Slot { get; private set; } = 1;
|
|
public int SendTimeout { get; private set; } = 3000;
|
|
public int ReceiveTimeout { get; private set; } = 3000;
|
|
|
|
private Plc _plc;
|
|
public Plc PlcContext => _plc;
|
|
|
|
public bool IsConnected => _plc?.IsConnected ?? false;
|
|
|
|
protected readonly SemaphoreSlim _commLock = new(1, 1);
|
|
|
|
public S7Device()
|
|
{
|
|
_plc = new Plc(CpuType, IPAddress, Rack, Slot);
|
|
}
|
|
|
|
public void ConfigureDevice(string ipAddress, CpuType cpuType, short rack = 0, short slot = 1, int sendTimeout = 3000, int receiveTimeout = 3000)
|
|
{
|
|
IPAddress = ipAddress;
|
|
CpuType = cpuType;
|
|
Rack = rack;
|
|
Slot = slot;
|
|
SendTimeout = sendTimeout;
|
|
ReceiveTimeout = receiveTimeout;
|
|
}
|
|
|
|
public virtual async Task<bool> ConnectAsync(CancellationToken ct = default)
|
|
{
|
|
await _commLock.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (_plc != null && _plc.IsConnected)
|
|
{
|
|
if (_plc.IP == IPAddress && _plc.CPU == CpuType && _plc.Rack == Rack && _plc.Slot == Slot)
|
|
return true;
|
|
}
|
|
|
|
if (_plc != null)
|
|
{
|
|
_plc.Close();
|
|
}
|
|
|
|
_plc = new Plc(CpuType, IPAddress, Rack, Slot)
|
|
{
|
|
ReadTimeout = ReceiveTimeout,
|
|
WriteTimeout = SendTimeout
|
|
};
|
|
|
|
await _plc.OpenAsync();
|
|
return _plc.IsConnected;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"[S7Device] 连接异常: IP={IPAddress}, CPU={CpuType}, Error={ex.Message}");
|
|
System.Diagnostics.Debug.WriteLine($"[S7Device] 异常堆栈: {ex.StackTrace}");
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
_commLock.Release();
|
|
}
|
|
}
|
|
|
|
public virtual void Close()
|
|
{
|
|
if (_plc != null && _plc.IsConnected)
|
|
_plc.Close();
|
|
}
|
|
|
|
public async Task WriteAsync(string address, object value, CancellationToken ct = default)
|
|
{
|
|
await _commLock.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (!IsConnected) throw new InvalidOperationException("PLC未连接。");
|
|
|
|
await _plc.WriteAsync(address, value)
|
|
.WaitAsync(TimeSpan.FromMilliseconds(SendTimeout), ct);
|
|
}
|
|
finally
|
|
{
|
|
_commLock.Release();
|
|
}
|
|
}
|
|
|
|
public async Task<object> ReadAsync(string address, CancellationToken ct = default)
|
|
{
|
|
await _commLock.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (!IsConnected) throw new InvalidOperationException("PLC未连接。");
|
|
|
|
return await _plc.ReadAsync(address)
|
|
.WaitAsync(TimeSpan.FromMilliseconds(ReceiveTimeout), ct);
|
|
}
|
|
finally
|
|
{
|
|
_commLock.Release();
|
|
}
|
|
}
|
|
|
|
public async Task<T> ReadAsync<T>(string address, CancellationToken ct = default)
|
|
{
|
|
var result = await ReadAsync(address, ct);
|
|
|
|
System.Diagnostics.Debug.WriteLine($"[S7Device.ReadAsync<T>] 地址={address}, 返回类型={result?.GetType().Name ?? "null"}, 值={result}");
|
|
|
|
try
|
|
{
|
|
if (result is IConvertible convertible)
|
|
{
|
|
return (T)Convert.ChangeType(convertible, typeof(T));
|
|
}
|
|
return (T)result;
|
|
}
|
|
catch (InvalidCastException ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"[S7Device.ReadAsync<T>] 类型转换失败: 目标类型={typeof(T).Name}, 实际类型={result.GetType().Name}, 值={result}, 异常={ex.Message}");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public async Task<byte[]> ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken ct = default)
|
|
{
|
|
await _commLock.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (!IsConnected) throw new InvalidOperationException("PLC未连接。");
|
|
|
|
return await _plc.ReadBytesAsync(dataType, db, startByteAdr, count)
|
|
.WaitAsync(TimeSpan.FromMilliseconds(ReceiveTimeout), ct);
|
|
}
|
|
finally
|
|
{
|
|
_commLock.Release();
|
|
}
|
|
}
|
|
|
|
public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value, CancellationToken ct = default)
|
|
{
|
|
await _commLock.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (!IsConnected) throw new InvalidOperationException("PLC未连接。");
|
|
|
|
await _plc.WriteBytesAsync(dataType, db, startByteAdr, value)
|
|
.WaitAsync(TimeSpan.FromMilliseconds(SendTimeout), ct);
|
|
}
|
|
finally
|
|
{
|
|
_commLock.Release();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_plc?.Close();
|
|
_commLock?.Dispose();
|
|
}
|
|
}
|
|
} |