refactor(driver-s7): extract S7DriverOptions to .Contracts with parallel CpuType enum

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.
This commit is contained in:
Joseph Doherty
2026-05-28 09:08:27 -04:00
parent a88721ce31
commit 9f62f2c242
11 changed files with 57 additions and 13 deletions
+1
View File
@@ -27,6 +27,7 @@
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Addressing/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Addressing.csproj" />
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Contracts.csproj" />
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7/ZB.MOM.WW.OtOpcUa.Driver.S7.csproj" />
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts/ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj" />
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip/ZB.MOM.WW.OtOpcUa.Driver.AbCip.csproj" />
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Contracts/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Contracts.csproj" />
<Project Path="src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.csproj" />
@@ -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;
/// <summary>Gets the rack number.</summary>
[CommandOption("rack", Description = "Rack number (default 0 — single-rack).")]
@@ -0,0 +1,18 @@
namespace ZB.MOM.WW.OtOpcUa.Driver.S7;
/// <summary>
/// CPU family used during S7 ISO-on-TCP handshake. Mirrors the value set of
/// <c>S7.Net.CpuType</c> (NuGet package S7netplus) so the contracts project stays
/// dependency-free. The runtime <c>S7Driver</c> maps this to the underlying
/// <c>S7.Net.CpuType</c> via <c>S7CpuTypeMap</c>.
/// </summary>
public enum S7CpuType
{
S7200 = 0,
Logo0BA8 = 1,
S7200Smart = 2,
S7300 = 10,
S7400 = 20,
S71200 = 30,
S71500 = 40,
}
@@ -1,5 +1,3 @@
using S7NetCpuType = global::S7.Net.CpuType;
namespace ZB.MOM.WW.OtOpcUa.Driver.S7;
/// <summary>
@@ -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.
/// </summary>
public S7NetCpuType CpuType { get; init; } = S7NetCpuType.S71500;
public S7CpuType CpuType { get; init; } = S7CpuType.S71500;
/// <summary>
/// Hardware rack number. Almost always 0; relevant only for distributed S7-400 racks
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<!-- NO PackageReference. NO ProjectReference. -->
</Project>
@@ -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),
};
}
@@ -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.
@@ -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<S7NetCpuType>(dto.CpuType, driverInstanceId, "CpuType",
fallback: S7NetCpuType.S71500),
CpuType = ParseEnum<S7CpuType>(dto.CpuType, driverInstanceId, "CpuType",
fallback: S7CpuType.S71500),
Rack = dto.Rack ?? 0,
Slot = dto.Slot ?? 0,
Timeout = TimeSpan.FromMilliseconds(dto.TimeoutMs ?? 5_000),
@@ -15,6 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Core\ZB.MOM.WW.OtOpcUa.Core.Abstractions\ZB.MOM.WW.OtOpcUa.Core.Abstractions.csproj"/>
<ProjectReference Include="..\..\Core\ZB.MOM.WW.OtOpcUa.Core\ZB.MOM.WW.OtOpcUa.Core.csproj"/>
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts\ZB.MOM.WW.OtOpcUa.Driver.S7.Contracts.csproj"/>
</ItemGroup>
<ItemGroup>
@@ -1,5 +1,3 @@
using S7NetCpuType = global::S7.Net.CpuType;
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500;
/// <summary>
@@ -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),
@@ -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");
}