diff --git a/ZB.MOM.WW.OtOpcUa.slnx b/ZB.MOM.WW.OtOpcUa.slnx
index 34b52687..30038332 100644
--- a/ZB.MOM.WW.OtOpcUa.slnx
+++ b/ZB.MOM.WW.OtOpcUa.slnx
@@ -32,6 +32,7 @@
+
diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/TwinCATDataType.cs
similarity index 51%
rename from src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs
rename to src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/TwinCATDataType.cs
index 9b0900aa..8f6851d1 100644
--- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataType.cs
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/TwinCATDataType.cs
@@ -1,5 +1,3 @@
-using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
-
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
///
@@ -34,30 +32,3 @@ public enum TwinCATDataType
/// UDT / FB instance. Resolved per member at discovery time.
Structure,
}
-
-/// Extension methods for TwinCATDataType.
-public static class TwinCATDataTypeExtensions
-{
- /// Maps a TwinCAT data type to the equivalent driver data type.
- /// The TwinCAT data type to convert.
- /// The corresponding driver data type.
- public static DriverDataType ToDriverDataType(this TwinCATDataType t) => t switch
- {
- TwinCATDataType.Bool => DriverDataType.Boolean,
- TwinCATDataType.SInt => DriverDataType.Int16, // signed 8-bit — no narrower OPC UA atom
- TwinCATDataType.USInt => DriverDataType.UInt16, // unsigned 8-bit — no narrower OPC UA atom
- TwinCATDataType.Int => DriverDataType.Int16,
- TwinCATDataType.UInt => DriverDataType.UInt16,
- TwinCATDataType.DInt => DriverDataType.Int32,
- TwinCATDataType.UDInt => DriverDataType.UInt32,
- TwinCATDataType.LInt => DriverDataType.Int64,
- TwinCATDataType.ULInt => DriverDataType.UInt64,
- TwinCATDataType.Real => DriverDataType.Float32,
- TwinCATDataType.LReal => DriverDataType.Float64,
- TwinCATDataType.String or TwinCATDataType.WString => DriverDataType.String,
- TwinCATDataType.Time or TwinCATDataType.Date
- or TwinCATDataType.DateTime or TwinCATDataType.TimeOfDay => DriverDataType.UInt32,
- TwinCATDataType.Structure => DriverDataType.String,
- _ => DriverDataType.Int32,
- };
-}
diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/TwinCATDriverOptions.cs
similarity index 95%
rename from src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs
rename to src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/TwinCATDriverOptions.cs
index 22072c29..24aad19a 100644
--- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriverOptions.cs
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/TwinCATDriverOptions.cs
@@ -22,7 +22,7 @@ public sealed class TwinCATDriverOptions
/// rather than the driver polling. Strictly better for latency + CPU when the target
/// supports it (TC2 + TC3 PLC runtimes always do; some soft-PLC / third-party ADS
/// implementations may not). When false, the driver falls through to the shared
- /// — same semantics as the other
+ /// PollGroupEngine — same semantics as the other
/// libplctag-backed drivers. Set false for deployments where the AMS router has
/// notification limits you can't raise.
///
@@ -50,7 +50,7 @@ public sealed class TwinCATDriverOptions
///
/// One TwinCAT target. must parse via
-/// ; misconfigured devices fail driver initialisation.
+/// TwinCATAmsAddress.TryParse; misconfigured devices fail driver initialisation.
///
public sealed record TwinCATDeviceOptions(
string HostAddress,
diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts.csproj b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts.csproj
new file mode 100644
index 00000000..d911061a
--- /dev/null
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts.csproj
@@ -0,0 +1,9 @@
+
+
+ net10.0
+ enable
+ enable
+ true
+
+
+
diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataTypeExtensions.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataTypeExtensions.cs
new file mode 100644
index 00000000..bd070be0
--- /dev/null
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDataTypeExtensions.cs
@@ -0,0 +1,30 @@
+using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
+
+namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
+
+/// Extension methods for TwinCATDataType.
+public static class TwinCATDataTypeExtensions
+{
+ /// Maps a TwinCAT data type to the equivalent driver data type.
+ /// The TwinCAT data type to convert.
+ /// The corresponding driver data type.
+ public static DriverDataType ToDriverDataType(this TwinCATDataType t) => t switch
+ {
+ TwinCATDataType.Bool => DriverDataType.Boolean,
+ TwinCATDataType.SInt => DriverDataType.Int16, // signed 8-bit — no narrower OPC UA atom
+ TwinCATDataType.USInt => DriverDataType.UInt16, // unsigned 8-bit — no narrower OPC UA atom
+ TwinCATDataType.Int => DriverDataType.Int16,
+ TwinCATDataType.UInt => DriverDataType.UInt16,
+ TwinCATDataType.DInt => DriverDataType.Int32,
+ TwinCATDataType.UDInt => DriverDataType.UInt32,
+ TwinCATDataType.LInt => DriverDataType.Int64,
+ TwinCATDataType.ULInt => DriverDataType.UInt64,
+ TwinCATDataType.Real => DriverDataType.Float32,
+ TwinCATDataType.LReal => DriverDataType.Float64,
+ TwinCATDataType.String or TwinCATDataType.WString => DriverDataType.String,
+ TwinCATDataType.Time or TwinCATDataType.Date
+ or TwinCATDataType.DateTime or TwinCATDataType.TimeOfDay => DriverDataType.UInt32,
+ TwinCATDataType.Structure => DriverDataType.String,
+ _ => DriverDataType.Int32,
+ };
+}
diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.csproj b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.csproj
index 4024f26f..5c41789a 100644
--- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.csproj
+++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.csproj
@@ -13,6 +13,7 @@
+