using S7NetCpuType = global::S7.Net.CpuType; namespace ZB.MOM.WW.OtOpcUa.Driver.S7; /// /// Siemens S7 native (S7comm / ISO-on-TCP port 102) driver configuration. Bound from the /// driver's DriverConfig JSON at DriverHost.RegisterAsync. Unlike the Modbus /// driver the S7 driver uses the PLC's *native* protocol — port 102 ISO-on-TCP rather /// than Modbus's 502, and S7-specific area codes (DB, M, I, Q) rather than holding- /// register / coil tables. /// /// /// /// The driver requires PUT/GET communication enabled in the TIA Portal /// hardware config for S7-1200/1500. The factory default disables PUT/GET access, /// so a driver configured against a freshly-flashed CPU will see a hard error /// (S7.Net surfaces it as Plc.ReadAsync returning ErrorCode.Accessing). /// The driver maps that specifically to BadNotSupported and flags it as a /// configuration alert rather than a transient fault — blind Polly retry is wasted /// effort when the PLC will keep refusing every request. /// /// /// See docs/v2/driver-specs.md §5 for the full specification. /// /// public sealed class S7DriverOptions { /// PLC IP address or hostname. public string Host { get; init; } = "127.0.0.1"; /// TCP port. ISO-on-TCP is 102 on every S7 model; override only for unusual NAT setups. public int Port { get; init; } = 102; /// /// 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; /// /// Hardware rack number. Almost always 0; relevant only for distributed S7-400 racks /// with multiple CPUs. /// public short Rack { get; init; } = 0; /// /// CPU slot. Conventions per family: S7-300 = slot 2, S7-400 = slot 2 or 3, /// S7-1200 / S7-1500 = slot 0 (onboard PN). S7.Net uses this to build the remote /// TSAP. Wrong slot → connection refused during handshake. /// public short Slot { get; init; } = 0; /// Connect + per-operation timeout. public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(5); /// Pre-declared tag map. S7 has a symbol-table protocol but S7.Net does not expose it, so the driver operates off a static tag list configured per-site. Address grammar documented in S7AddressParser (PR 63). public IReadOnlyList Tags { get; init; } = []; /// /// Background connectivity-probe settings. When enabled, the driver runs a tick loop /// that issues a cheap read against every /// and raises OnHostStatusChanged on /// Running ↔ Stopped transitions. /// public S7ProbeOptions Probe { get; init; } = new(); } public sealed class S7ProbeOptions { public bool Enabled { get; init; } = true; public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5); public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2); /// /// Address to probe for liveness. DB1.DBW0 is the convention if the PLC project /// reserves a small fingerprint DB for health checks (per docs/v2/s7.md); /// if not, pick any valid Merker word like MW0. /// public string ProbeAddress { get; init; } = "MW0"; } /// /// One S7 variable as exposed by the driver. Addresses use S7.Net syntax — see /// S7AddressParser (PR 63) for the grammar. /// /// Tag name; OPC UA browse name + driver full reference. /// S7 address string, e.g. DB1.DBW0, M0.0, I0.0, QD4. Grammar documented in S7AddressParser (PR 63). /// Logical data type — drives the underlying S7.Net read/write width. /// When true the driver accepts writes for this tag. /// For DataType = String: S7-string max length. Default 254 (S7 max). /// /// Per docs/v2/plan.md decisions #44, #45, #143 — flag a tag as safe to replay on /// write timeout / failure. Default false; writes do not auto-retry. Safe candidates /// on S7: DB word/dword set-points holding analog values, configuration DBs where the same /// value can be written again without side-effects. Unsafe: M (merker) bits or Q (output) /// coils that drive edge-triggered routines in the PLC program. /// public sealed record S7TagDefinition( string Name, string Address, S7DataType DataType, bool Writable = true, int StringLength = 254, bool WriteIdempotent = false); public enum S7DataType { Bool, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64, String, DateTime, }