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,
}