From 59856db96eb3969ba961fc9315603a744c0d47ea Mon Sep 17 00:00:00 2001 From: gcw_MV9p2JJN Date: Mon, 26 Jan 2026 11:38:02 +0800 Subject: [PATCH] PlcConntectHepler --- .../PLCBackground/PlcConntectHepler.cs | 133 ++++++++++++++++++ .../PLCBackground/PlcPollingServiceOP72.cs | 70 +++++++++ 2 files changed, 203 insertions(+) create mode 100644 RIZO.Service/PLCBackground/PlcConntectHepler.cs create mode 100644 RIZO.Service/PLCBackground/PlcPollingServiceOP72.cs diff --git a/RIZO.Service/PLCBackground/PlcConntectHepler.cs b/RIZO.Service/PLCBackground/PlcConntectHepler.cs new file mode 100644 index 0000000..7b7ec49 --- /dev/null +++ b/RIZO.Service/PLCBackground/PlcConntectHepler.cs @@ -0,0 +1,133 @@ +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 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; + } + } + +} diff --git a/RIZO.Service/PLCBackground/PlcPollingServiceOP72.cs b/RIZO.Service/PLCBackground/PlcPollingServiceOP72.cs new file mode 100644 index 0000000..bd48532 --- /dev/null +++ b/RIZO.Service/PLCBackground/PlcPollingServiceOP72.cs @@ -0,0 +1,70 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using RIZO.Service.PLC; +using S7.Net; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace RIZO.Service.PLCBackground +{ + + + public class PlcPollingServiceOP72 : BackgroundService + { + private readonly ILogger _logger; + private PlcConntectHepler _plcService; + private readonly TimeSpan _pollingInterval = TimeSpan.FromSeconds(5); + private readonly string _ipAddress = "192.168.0.1"; + private readonly CpuType _cpuType = CpuType.S71500; + + public PlcPollingServiceOP72(ILogger logger) + { + _logger = logger; + } + + + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + _logger.LogInformation("PLC Polling Service started"); + + // 使用工厂方法创建服务实例 + using (_plcService = new PlcConntectHepler(_ipAddress, _cpuType)) + { + while (!stoppingToken.IsCancellationRequested) + { + try + { + // 使用异步读写方法 + var data1 = await _plcService.ReadAsync("DB1.DBW0"); + var data2 = await _plcService.ReadAsync("DB1.DBD4"); + var flag = await _plcService.ReadAsync("M10.0"); + + _logger.LogInformation($"DB1.DBW0: {data1}, DB1.DBD4: {data2}, M10.0: {flag}"); + + await _plcService.WriteAsync("DB1.DBW10", (short)123); + await _plcService.WriteAsync("DB1.DBD20", 45.67d); + + await Task.Delay(_pollingInterval, stoppingToken); + } + catch (OperationCanceledException) + { + _logger.LogInformation("PLC Polling Service is stopping"); + break; + } + catch (Exception ex) + { + _logger.LogError(ex, "PLC polling error"); + await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); + } + } + } + + _logger.LogInformation("PLC Polling Service stopped"); + } + + + } +} +