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");
}