新增信号交互进程插件
This commit is contained in:
@@ -5,9 +5,17 @@ using IoTClient.Common.Enums;
|
||||
|
||||
namespace StandardScene.Signal.Plc
|
||||
{
|
||||
/// <summary>西门子 S7 长连接。地址兼容 Hsl 的 DB1.0 与 IoTClient 的 DB1.DBB0。</summary>
|
||||
/// <summary>
|
||||
/// 西门子 S7 长连接封装(IoTClient)。一个机构一个实例,由对应 Worker 独占。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 字节地址兼容老 Hsl 写法 <c>DB1.0</c> 与 IoTClient 写法 <c>DB1.DBB0</c>;
|
||||
/// 心跳位地址保持原样(如 <c>DB1.DBX2.0</c>),不做 DBB 转换。
|
||||
/// 连接失败时读/写返回 false,由 Worker 标断线,不在这里抛给扫车线程。
|
||||
/// </remarks>
|
||||
public sealed class SiemensPlcSession : IDisposable
|
||||
{
|
||||
/// <summary>匹配 Hsl 风格「DB块号.字节偏移」,捕获组 1=DB,2=偏移。</summary>
|
||||
private static readonly Regex BareDbByte = new Regex(@"^DB(\d+)\.(\d+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
private readonly SiemensVersion _version;
|
||||
@@ -17,6 +25,10 @@ namespace StandardScene.Signal.Plc
|
||||
private SiemensClient _client;
|
||||
private readonly object _sync = new object();
|
||||
|
||||
/// <param name="version">进程字段 PlcVersion,如 S7_1500。</param>
|
||||
/// <param name="ip">机构 IP。</param>
|
||||
/// <param name="port">S7 端口,通常 102。</param>
|
||||
/// <param name="slot">机架槽号,S7-1500 常见 1。</param>
|
||||
public SiemensPlcSession(string version, string ip, int port, int slot)
|
||||
{
|
||||
_version = ParseVersion(version);
|
||||
@@ -25,6 +37,7 @@ namespace StandardScene.Signal.Plc
|
||||
_slot = (byte)Math.Max(0, slot);
|
||||
}
|
||||
|
||||
/// <summary>当前客户端是否已 Open 成功。未创建客户端时为 false。</summary>
|
||||
public bool Connected
|
||||
{
|
||||
get
|
||||
@@ -33,6 +46,7 @@ namespace StandardScene.Signal.Plc
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>惰性创建客户端并 Open。已连接则直接 true;失败返回 false 不抛。</summary>
|
||||
public bool EnsureOpen()
|
||||
{
|
||||
lock (_sync)
|
||||
@@ -53,6 +67,7 @@ namespace StandardScene.Signal.Plc
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>读一字节。地址会先规范化;未连接或失败时 value=0 且返回 false。</summary>
|
||||
public bool TryReadByte(string address, out byte value)
|
||||
{
|
||||
value = 0;
|
||||
@@ -72,6 +87,7 @@ namespace StandardScene.Signal.Plc
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>写一字节(进入中/到位等)。失败返回 false。</summary>
|
||||
public bool TryWriteByte(string address, byte value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address) || !EnsureOpen())
|
||||
@@ -87,6 +103,7 @@ namespace StandardScene.Signal.Plc
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>读心跳位。地址不做 DBB 转换。</summary>
|
||||
public bool TryReadBool(string address, out bool value)
|
||||
{
|
||||
value = false;
|
||||
@@ -106,6 +123,7 @@ namespace StandardScene.Signal.Plc
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>写心跳位(通常写当前值的反码,让 PLC 看到翻转)。</summary>
|
||||
public bool TryWriteBool(string address, bool value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address) || !EnsureOpen())
|
||||
@@ -121,6 +139,7 @@ namespace StandardScene.Signal.Plc
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>关闭并丢弃客户端,下次 EnsureOpen 会新建。</summary>
|
||||
public void Close()
|
||||
{
|
||||
lock (_sync)
|
||||
@@ -133,6 +152,9 @@ namespace StandardScene.Signal.Plc
|
||||
|
||||
public void Dispose() => Close();
|
||||
|
||||
/// <summary>
|
||||
/// <c>DB1.0</c> → <c>DB1.DBB0</c>;已是 DBB/DBW/DBX 的地址原样返回。
|
||||
/// </summary>
|
||||
internal static string NormalizeByteAddress(string address)
|
||||
{
|
||||
var addr = address.Trim();
|
||||
@@ -140,6 +162,7 @@ namespace StandardScene.Signal.Plc
|
||||
return m.Success ? $"DB{m.Groups[1].Value}.DBB{m.Groups[2].Value}" : addr;
|
||||
}
|
||||
|
||||
/// <summary>空或无法解析时默认 S7_1500。允许把 S7-1500 写成带连字符。</summary>
|
||||
internal static SiemensVersion ParseVersion(string version)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(version))
|
||||
|
||||
Reference in New Issue
Block a user