134 lines
4.1 KiB
C#
134 lines
4.1 KiB
C#
using System;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using S7.Net; // 确保引用 S7.Net 库
|
||
|
||
namespace RIZO.Service.PLC
|
||
{
|
||
|
||
|
||
|
||
public class PlcConntectHepler : IDisposable
|
||
{
|
||
private Plc _plc;
|
||
private readonly string _ipAddress;
|
||
private readonly CpuType _cpuType;
|
||
private readonly short _rack;
|
||
private readonly short _slot;
|
||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
|
||
private bool _disposed;
|
||
|
||
public PlcConntectHepler(string ipAddress, CpuType cpuType = CpuType.S71200, short rack = 0, short slot = 1)
|
||
{
|
||
_ipAddress = ipAddress;
|
||
_cpuType = cpuType;
|
||
_rack = rack;
|
||
_slot = slot;
|
||
}
|
||
|
||
private async Task ConnectAsync(CancellationToken cancellationToken = default)
|
||
{
|
||
int maxRetries = 3;
|
||
int retryDelayMs = 2000;
|
||
int attempt = 0;
|
||
|
||
while (attempt < maxRetries)
|
||
{
|
||
attempt++;
|
||
try
|
||
{
|
||
_plc = new Plc(_cpuType, _ipAddress, _rack, _slot);
|
||
await Task.Run(() => _plc.Open(), cancellationToken); // 在线程池中执行同步Open
|
||
Console.WriteLine($"成功连接到PLC: {_ipAddress} (尝试{attempt}/{maxRetries})");
|
||
return;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"连接尝试 {attempt}/{maxRetries} 失败: {ex.Message}");
|
||
|
||
if (attempt < maxRetries)
|
||
{
|
||
Console.WriteLine($"{retryDelayMs / 1000}秒后重试...");
|
||
await Task.Delay(retryDelayMs, cancellationToken);
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine("无法建立PLC连接,请检查网络和设备状态");
|
||
_plc?.Close();
|
||
_plc = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public async Task<object> ReadAsync(string address, CancellationToken cancellationToken = default)
|
||
{
|
||
await _semaphore.WaitAsync(cancellationToken);
|
||
try
|
||
{
|
||
if (_plc == null || !_plc.IsConnected)
|
||
{
|
||
await ConnectAsync(cancellationToken);
|
||
if (_plc == null || !_plc.IsConnected)
|
||
throw new InvalidOperationException("PLC未连接");
|
||
}
|
||
|
||
return await Task.Run(() => _plc.Read(address), cancellationToken);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Read error: {ex.Message}");
|
||
return null;
|
||
}
|
||
finally
|
||
{
|
||
_semaphore.Release();
|
||
}
|
||
}
|
||
|
||
public async Task WriteAsync(string address, object value, CancellationToken cancellationToken = default)
|
||
{
|
||
await _semaphore.WaitAsync(cancellationToken);
|
||
try
|
||
{
|
||
if (_plc == null || !_plc.IsConnected)
|
||
{
|
||
await ConnectAsync(cancellationToken);
|
||
if (_plc == null || !_plc.IsConnected)
|
||
throw new InvalidOperationException("PLC未连接");
|
||
}
|
||
|
||
await Task.Run(() => _plc.Write(address, value), cancellationToken);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Write error: {ex.Message}");
|
||
}
|
||
finally
|
||
{
|
||
_semaphore.Release();
|
||
}
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
Dispose(true);
|
||
GC.SuppressFinalize(this);
|
||
}
|
||
|
||
protected virtual void Dispose(bool disposing)
|
||
{
|
||
if (_disposed) return;
|
||
|
||
if (disposing)
|
||
{
|
||
_semaphore.Dispose();
|
||
_plc?.Close();
|
||
(_plc as IDisposable)?.Dispose();
|
||
}
|
||
_disposed = true;
|
||
}
|
||
}
|
||
|
||
}
|