设备基础命令

This commit is contained in:
“hsc”
2026-06-09 15:51:00 +08:00
parent c29519080a
commit a355373423
17 changed files with 1119 additions and 8 deletions

View File

@@ -0,0 +1,169 @@
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;
// S7.Net 的 Plc.IsConnected 属性内部会通过 Socket 状态进行判断
public bool IsConnected => _plc?.IsConnected ?? false;
// 统一线程锁
protected readonly SemaphoreSlim _commLock = new(1, 1);
public S7Device()
{
// 初始化默认配置
_plc = new Plc(CpuType, IPAddress, Rack, Slot);
}
/// <summary>
/// 设备参数配置(符合你的命名风格)
/// </summary>
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
{
// 如果已经连接,检查当前的 IP 和 CPU 类型是否一致,一致则直接复用
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 对象并配置超时
_plc = new Plc(CpuType, IPAddress, Rack, Slot)
{
ReadTimeout = ReceiveTimeout,
WriteTimeout = SendTimeout
};
// 部分版本 S7.Net 的 OpenAsync 本身不接受 CancellationToken我们通过 WaitAsync 实现超时
await _plc.OpenAsync().WaitAsync(TimeSpan.FromMilliseconds(SendTimeout), ct);
return _plc.IsConnected;
}
catch
{
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);
return (T)result;
}
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();
}
}
}