@@ -81,6 +81,111 @@ public sealed class S7DriverOptions
|
||||
/// opt out of merging regardless of this knob.
|
||||
/// </remarks>
|
||||
public int BlockCoalescingGapBytes { get; init; } = S7BlockCoalescingPlanner.DefaultGapMergeBytes;
|
||||
|
||||
/// <summary>
|
||||
/// ISO-on-TCP / S7comm "connection class" selector. Hardened S7-1500 CPUs and some
|
||||
/// ET 200SP / S7-1200 firmware variants reject the default <b>PG-class</b> TSAP that
|
||||
/// S7netplus picks under <see cref="TsapMode.Auto"/> and require an <b>OP-class</b>
|
||||
/// or <b>S7-Basic-class</b> TSAP instead. Picking the wrong class produces the same
|
||||
/// failure shape as picking the wrong slot — connection refused at COTP handshake
|
||||
/// time, before any S7comm PDU is sent. See <c>docs/v2/s7.md</c> "TSAP / Connection
|
||||
/// Type" section for the raw-TSAP byte table and the hardened-CPU motivation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <see cref="TsapMode.Auto"/> preserves existing behaviour — S7netplus picks
|
||||
/// the TSAP pair from the configured <see cref="CpuType"/> via its
|
||||
/// <c>TsapPair.GetDefaultTsapPair</c>. Use <see cref="TsapMode.Pg"/> /
|
||||
/// <see cref="TsapMode.Op"/> / <see cref="TsapMode.S7Basic"/> to force a specific
|
||||
/// class, or <see cref="TsapMode.Other"/> together with <see cref="LocalTsap"/>
|
||||
/// and <see cref="RemoteTsap"/> for a fully-manual escape hatch. Explicit
|
||||
/// <see cref="LocalTsap"/> / <see cref="RemoteTsap"/> overrides win even under
|
||||
/// <see cref="TsapMode.Pg"/> / <see cref="TsapMode.Op"/> / <see cref="TsapMode.S7Basic"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public TsapMode TsapMode { get; init; } = TsapMode.Auto;
|
||||
|
||||
/// <summary>
|
||||
/// Optional fully-manual local TSAP override (16-bit big-endian word — high byte =
|
||||
/// class selector, low byte = caller-defined). Required (together with
|
||||
/// <see cref="RemoteTsap"/>) when <see cref="TsapMode"/> is
|
||||
/// <see cref="TsapMode.Other"/>. Wins over the class-derived default under any
|
||||
/// non-<see cref="TsapMode.Auto"/> mode.
|
||||
/// </summary>
|
||||
public ushort? LocalTsap { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional fully-manual remote TSAP override (16-bit big-endian word — high byte =
|
||||
/// class selector, low byte = <c>(rack << 5) | slot</c> per the S7 spec).
|
||||
/// Required (together with <see cref="LocalTsap"/>) when <see cref="TsapMode"/> is
|
||||
/// <see cref="TsapMode.Other"/>. Wins over the class-derived default under any
|
||||
/// non-<see cref="TsapMode.Auto"/> mode.
|
||||
/// </summary>
|
||||
public ushort? RemoteTsap { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ISO-on-TCP / S7comm connection class. Picks the high byte of the TSAP pair used
|
||||
/// during COTP handshake. See <c>docs/v2/s7.md</c> "TSAP / Connection Type" section
|
||||
/// for the raw-byte table and the hardened-CPU motivation.
|
||||
/// </summary>
|
||||
public enum TsapMode
|
||||
{
|
||||
/// <summary>S7netplus picks the TSAP pair from <see cref="S7DriverOptions.CpuType"/>. Existing behaviour.</summary>
|
||||
Auto,
|
||||
/// <summary>PG class — high byte 0x01. Default for development laptops / TIA Portal.</summary>
|
||||
Pg,
|
||||
/// <summary>OP class — high byte 0x02. Required by some hardened S7-1500 / ET 200SP deployments.</summary>
|
||||
Op,
|
||||
/// <summary>S7-Basic class — high byte 0x03. Used by S7-Basic clients (e.g. some HMI panels and the WinCC BasicPanel SDK).</summary>
|
||||
S7Basic,
|
||||
/// <summary>Caller-supplied <see cref="S7DriverOptions.LocalTsap"/> + <see cref="S7DriverOptions.RemoteTsap"/>. Both must be set or driver init throws.</summary>
|
||||
Other,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw-TSAP byte constants per ISO-on-TCP / S7comm connection class. The "high byte"
|
||||
/// is the class selector documented in the Siemens function manual; the local TSAP's
|
||||
/// low byte is conventionally 0x00 (caller / unprivileged) and the remote TSAP's low
|
||||
/// byte is <c>(rack << 5) | slot</c> per the spec. Mirrored in
|
||||
/// <c>docs/v2/s7.md</c> "TSAP / Connection Type" table.
|
||||
/// </summary>
|
||||
public static class S7TsapDefaults
|
||||
{
|
||||
/// <summary>PG-class high byte = 0x01.</summary>
|
||||
public const byte PgClassHighByte = 0x01;
|
||||
|
||||
/// <summary>OP-class high byte = 0x02.</summary>
|
||||
public const byte OpClassHighByte = 0x02;
|
||||
|
||||
/// <summary>S7-Basic-class high byte = 0x03.</summary>
|
||||
public const byte S7BasicClassHighByte = 0x03;
|
||||
|
||||
/// <summary>Build the local TSAP (16-bit BE): <c>class << 8 | 0x00</c>.</summary>
|
||||
public static ushort BuildLocalTsap(byte classHighByte) => (ushort)(classHighByte << 8);
|
||||
|
||||
/// <summary>
|
||||
/// Build the remote TSAP (16-bit BE): <c>class << 8 | ((rack & 0x07) << 5 | (slot & 0x1F))</c>.
|
||||
/// Matches the convention used by S7netplus's <c>TsapPair.GetDefaultTsapPair</c> for the remote endpoint.
|
||||
/// </summary>
|
||||
public static ushort BuildRemoteTsap(byte classHighByte, int rack, int slot)
|
||||
{
|
||||
if (rack < 0 || rack > 15)
|
||||
throw new ArgumentOutOfRangeException(nameof(rack), rack, "rack must be 0..15");
|
||||
if (slot < 0 || slot > 31)
|
||||
throw new ArgumentOutOfRangeException(nameof(slot), slot, "slot must be 0..31");
|
||||
return (ushort)((classHighByte << 8) | ((rack & 0x07) << 5) | (slot & 0x1F));
|
||||
}
|
||||
|
||||
/// <summary>Pick the class high-byte for a non-<see cref="TsapMode.Auto"/> / non-<see cref="TsapMode.Other"/> mode.</summary>
|
||||
public static byte HighByteFor(TsapMode mode) => mode switch
|
||||
{
|
||||
TsapMode.Pg => PgClassHighByte,
|
||||
TsapMode.Op => OpClassHighByte,
|
||||
TsapMode.S7Basic => S7BasicClassHighByte,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode,
|
||||
"HighByteFor only handles Pg / Op / S7Basic; Auto and Other are caller-handled"),
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class S7ProbeOptions
|
||||
|
||||
Reference in New Issue
Block a user