From 9f62f2c242ac58c033a8cc18c4f95e7e61a2e2c7 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 28 May 2026 09:08:27 -0400 Subject: [PATCH] refactor(driver-s7): extract S7DriverOptions to .Contracts with parallel CpuType enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces Driver.S7.Contracts (dependency-free POCO project) and moves S7DriverOptions / S7ProbeOptions / S7TagDefinition / S7DataType into it. Adds S7CpuType enum mirroring S7.Net.CpuType exactly (7 values with explicit integer codes). Runtime S7CpuTypeMap bridges S7CpuType โ†’ S7.Net.CpuType at the single Plc construction site in S7Driver.InitializeAsync. S7DriverFactoryExtensions and S7CommandBase updated to use S7CpuType; test files updated to match (S7_1500Profile, S7DriverScaffoldTests). AdminUI can now reference Driver.S7.Contracts without pulling in S7netplus. --- ZB.MOM.WW.OtOpcUa.slnx | 1 + .../S7CommandBase.cs | 3 +-- .../S7CpuType.cs | 18 ++++++++++++++++++ .../S7DriverOptions.cs | 4 +--- ...B.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj | 12 ++++++++++++ .../S7CpuTypeMap.cs | 18 ++++++++++++++++++ .../ZB.MOM.WW.OtOpcUa.Driver.S7/S7Driver.cs | 2 +- .../S7DriverFactoryExtensions.cs | 5 ++--- .../ZB.MOM.WW.OtOpcUa.Driver.S7.csproj | 1 + .../S7_1500/S7_1500Profile.cs | 4 +--- .../S7DriverScaffoldTests.cs | 2 +- 11 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7CpuType.cs rename src/Drivers/{ZB.MOM.WW.OtOpcUa.Driver.S7 => ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts}/S7DriverOptions.cs (97%) create mode 100644 src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj create mode 100644 src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7CpuTypeMap.cs diff --git a/ZB.MOM.WW.OtOpcUa.slnx b/ZB.MOM.WW.OtOpcUa.slnx index 30038332..2d0ed744 100644 --- a/ZB.MOM.WW.OtOpcUa.slnx +++ b/ZB.MOM.WW.OtOpcUa.slnx @@ -27,6 +27,7 @@ + diff --git a/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/S7CommandBase.cs b/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/S7CommandBase.cs index a06f53ba..ecf725f5 100644 --- a/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/S7CommandBase.cs +++ b/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/S7CommandBase.cs @@ -1,6 +1,5 @@ using CliFx.Attributes; using ZB.MOM.WW.OtOpcUa.Driver.Cli.Common; -using S7NetCpuType = global::S7.Net.CpuType; namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Cli; @@ -24,7 +23,7 @@ public abstract class S7CommandBase : DriverCommandBase [CommandOption("cpu", 'c', Description = "S7 CPU family: S7200 / S7200Smart / S7300 / S7400 / S71200 / S71500 " + "(default S71500). Determines the ISO-TSAP slot byte.")] - public S7NetCpuType CpuType { get; init; } = S7NetCpuType.S71500; + public S7CpuType CpuType { get; init; } = S7CpuType.S71500; /// Gets the rack number. [CommandOption("rack", Description = "Rack number (default 0 โ€” single-rack).")] diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7CpuType.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7CpuType.cs new file mode 100644 index 00000000..2c739c89 --- /dev/null +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7CpuType.cs @@ -0,0 +1,18 @@ +namespace ZB.MOM.WW.OtOpcUa.Driver.S7; + +/// +/// CPU family used during S7 ISO-on-TCP handshake. Mirrors the value set of +/// S7.Net.CpuType (NuGet package S7netplus) so the contracts project stays +/// dependency-free. The runtime S7Driver maps this to the underlying +/// S7.Net.CpuType via S7CpuTypeMap. +/// +public enum S7CpuType +{ + S7200 = 0, + Logo0BA8 = 1, + S7200Smart = 2, + S7300 = 10, + S7400 = 20, + S71200 = 30, + S71500 = 40, +} diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverOptions.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7DriverOptions.cs similarity index 97% rename from src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverOptions.cs rename to src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7DriverOptions.cs index 4908078c..18a2e0c9 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverOptions.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/S7DriverOptions.cs @@ -1,5 +1,3 @@ -using S7NetCpuType = global::S7.Net.CpuType; - namespace ZB.MOM.WW.OtOpcUa.Driver.S7; /// @@ -35,7 +33,7 @@ public sealed class S7DriverOptions /// CPU family. Determines the ISO-TSAP slot byte that S7.Net uses during connection /// setup โ€” pick the family that matches the target PLC exactly. /// - public S7NetCpuType CpuType { get; init; } = S7NetCpuType.S71500; + public S7CpuType CpuType { get; init; } = S7CpuType.S71500; /// /// Hardware rack number. Almost always 0; relevant only for distributed S7-400 racks diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj new file mode 100644 index 00000000..52900ddb --- /dev/null +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj @@ -0,0 +1,12 @@ + + + + net10.0 + enable + enable + true + + + + + diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7CpuTypeMap.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7CpuTypeMap.cs new file mode 100644 index 00000000..9f591094 --- /dev/null +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7CpuTypeMap.cs @@ -0,0 +1,18 @@ +using S7NetCpuType = global::S7.Net.CpuType; + +namespace ZB.MOM.WW.OtOpcUa.Driver.S7; + +internal static class S7CpuTypeMap +{ + public static S7NetCpuType ToS7Net(S7CpuType type) => type switch + { + S7CpuType.S7200 => S7NetCpuType.S7200, + S7CpuType.Logo0BA8 => S7NetCpuType.Logo0BA8, + S7CpuType.S7200Smart => S7NetCpuType.S7200Smart, + S7CpuType.S7300 => S7NetCpuType.S7300, + S7CpuType.S7400 => S7NetCpuType.S7400, + S7CpuType.S71200 => S7NetCpuType.S71200, + S7CpuType.S71500 => S7NetCpuType.S71500, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), + }; +} diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7Driver.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7Driver.cs index 22a95ca6..312144dc 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7Driver.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7Driver.cs @@ -138,7 +138,7 @@ public sealed class S7Driver(S7DriverOptions options, string driverInstanceId, I // type is wired through. RejectUnsupportedTagDataTypes(); - var plc = new Plc(_options.CpuType, _options.Host, _options.Port, _options.Rack, _options.Slot); + var plc = new Plc(S7CpuTypeMap.ToS7Net(_options.CpuType), _options.Host, _options.Port, _options.Rack, _options.Slot); // S7netplus writes timeouts into the underlying TcpClient via Plc.WriteTimeout / // Plc.ReadTimeout (milliseconds). Set before OpenAsync so the handshake itself // honours the bound. diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverFactoryExtensions.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverFactoryExtensions.cs index 153ff5cd..0ca03032 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverFactoryExtensions.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/S7DriverFactoryExtensions.cs @@ -1,7 +1,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using ZB.MOM.WW.OtOpcUa.Core.Hosting; -using S7NetCpuType = global::S7.Net.CpuType; namespace ZB.MOM.WW.OtOpcUa.Driver.S7; @@ -60,8 +59,8 @@ public static class S7DriverFactoryExtensions { Host = dto.Host!, Port = dto.Port ?? 102, - CpuType = ParseEnum(dto.CpuType, driverInstanceId, "CpuType", - fallback: S7NetCpuType.S71500), + CpuType = ParseEnum(dto.CpuType, driverInstanceId, "CpuType", + fallback: S7CpuType.S71500), Rack = dto.Rack ?? 0, Slot = dto.Slot ?? 0, Timeout = TimeSpan.FromMilliseconds(dto.TimeoutMs ?? 5_000), diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/ZB.MOM.WW.OtOpcUa.Driver.S7.csproj b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/ZB.MOM.WW.OtOpcUa.Driver.S7.csproj index d34f0beb..239b1450 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/ZB.MOM.WW.OtOpcUa.Driver.S7.csproj +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/ZB.MOM.WW.OtOpcUa.Driver.S7.csproj @@ -15,6 +15,7 @@ + diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/S7_1500/S7_1500Profile.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/S7_1500/S7_1500Profile.cs index 81ddf9ef..c329e472 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/S7_1500/S7_1500Profile.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/S7_1500/S7_1500Profile.cs @@ -1,5 +1,3 @@ -using S7NetCpuType = global::S7.Net.CpuType; - namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500; /// @@ -34,7 +32,7 @@ public static class S7_1500Profile { Host = host, Port = port, - CpuType = S7NetCpuType.S71500, + CpuType = S7CpuType.S71500, Rack = 0, Slot = 0, Timeout = TimeSpan.FromSeconds(5), diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverScaffoldTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverScaffoldTests.cs index 43bad93f..b0e4b431 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverScaffoldTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/S7DriverScaffoldTests.cs @@ -18,7 +18,7 @@ public sealed class S7DriverScaffoldTests { var opts = new S7DriverOptions(); opts.Port.ShouldBe(102, "ISO-on-TCP is always 102 for S7; documented in driver-specs.md ยง5"); - opts.CpuType.ShouldBe(global::S7.Net.CpuType.S71500); + opts.CpuType.ShouldBe(S7CpuType.S71500); opts.Rack.ShouldBe((short)0); opts.Slot.ShouldBe((short)0, "S7-1200/1500 onboard PN ports are slot 0 by convention"); }