Files
lmxopcua/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport/Cip/ConnectionOptions.cs
T
Joseph Doherty 826312befe docs: fill missing XML docs and strip tracking IDs from src comments
Clears CommentChecker findings in src/ (3,280 -> 209, the remainder being false
positives like PLC-5/IEEE-754/M0.0) by adding missing summaries/params/returns,
normalising inheritdoc usage, and removing Gitea/review tracking IDs while keeping
the rationale they annotated. Comment-only: comment-stripped sources are identical
to the parent commit.
2026-10-15 06:14:58 -04:00

103 lines
5.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Cip;
/// <summary>How CIP requests reach the target's message router (review finding B3; the captures decide
/// each family's mode).</summary>
public enum CipRouting
{
/// <summary>Forward Open a class-3 connection, then SendUnitData. Logix and Micro800 (empty route).</summary>
Connected,
/// <summary>SendRRData wrapping each request in Unconnected Send (0x52) carrying the route.</summary>
UnconnectedSend,
/// <summary>SendRRData carrying the request bare; any configured CIP path is ignored (PCCC families).</summary>
Direct,
}
/// <summary>Per-device connection settings. Validated on assignment so an unusable value fails at the
/// configuration seam rather than on the wire.</summary>
public sealed record ConnectionOptions
{
/// <summary>Press safety floor: no setting may let Forward Opens to one device start closer together.</summary>
public static readonly TimeSpan MinimumForwardOpenInterval = TimeSpan.FromSeconds(1);
/// <summary>Originator serial shared by every connection this process opens.</summary>
private static readonly uint ProcessOriginatorSerial = (uint)Random.Shared.Next(1, int.MaxValue);
private readonly TimeSpan _timeout = TimeSpan.FromSeconds(5);
private readonly int _connectionSize = 4002;
private readonly TimeSpan _minForwardOpenInterval = MinimumForwardOpenInterval;
private readonly uint _rpiMicros = 2_000_000;
private readonly byte _timeoutMultiplier = 1;
private readonly TimeSpan? _keepAliveInterval;
/// <summary>How requests reach the target's message router.</summary>
public CipRouting Routing { get; init; } = CipRouting.Connected;
/// <summary>Pack queued requests into Multiple Service Packets (the scheduler's switch).</summary>
public bool AllowPacking { get; init; }
/// <summary>Bound on each single exchange (TCP connect, RegisterSession, Forward Open, request).
/// Must be finite and positive: an infinite timeout would let an abandoned exchange
/// hold the session's single-flight gate forever.</summary>
public TimeSpan Timeout
{
get => _timeout;
init => _timeout = value > TimeSpan.Zero && value != System.Threading.Timeout.InfiniteTimeSpan
? value
: throw new ArgumentOutOfRangeException(nameof(Timeout), value, "Timeout must be finite and positive.");
}
/// <summary>Requested connection size in bytes. Above 511 the open is a Large Forward Open (0x5B).</summary>
public int ConnectionSize
{
get => _connectionSize;
init => _connectionSize = value is >= 1 and <= ushort.MaxValue
? value
: throw new ArgumentOutOfRangeException(nameof(ConnectionSize), value, "Connection size must be 1..65535.");
}
/// <summary>Minimum time between Forward Open attempt starts for one device (≥ 1 s, press safety).</summary>
public TimeSpan MinForwardOpenInterval
{
get => _minForwardOpenInterval;
init => _minForwardOpenInterval = value >= MinimumForwardOpenInterval && value != System.Threading.Timeout.InfiniteTimeSpan
? value
: throw new ArgumentOutOfRangeException(nameof(MinForwardOpenInterval), value, "Must be finite and at least 1 s (press safety).");
}
/// <summary>Requested packet interval for both directions, in microseconds.</summary>
public uint RpiMicros
{
get => _rpiMicros;
init => _rpiMicros = value > 0 ? value : throw new ArgumentOutOfRangeException(nameof(RpiMicros), value, "RPI must be positive.");
}
/// <summary>Encoded connection timeout multiplier: the connection expires after RPI × (4 &lt;&lt; value).
/// The default 1 means ×8, so 2 s × 8 = 16 s.</summary>
public byte TimeoutMultiplier
{
get => _timeoutMultiplier;
init => _timeoutMultiplier = value <= 7 ? value : throw new ArgumentOutOfRangeException(nameof(TimeoutMultiplier), value, "Multiplier must be 0..7.");
}
/// <summary>How long an idle connected session waits before the target would drop it.</summary>
public TimeSpan ConnectionExpiry => TimeSpan.FromTicks(RpiMicros * 10L * (4L << TimeoutMultiplier));
/// <summary>Idle time after which a keep-alive is sent (Connected only). Defaults to half the
/// connection expiry: RPI × 8 / 2 = 8 s.</summary>
public TimeSpan KeepAliveInterval
{
get => _keepAliveInterval ?? ConnectionExpiry / 2;
init => _keepAliveInterval = value > TimeSpan.Zero && value != System.Threading.Timeout.InfiniteTimeSpan
? value
: throw new ArgumentOutOfRangeException(nameof(KeepAliveInterval), value, "Keep-alive interval must be finite and positive.");
}
/// <summary>The vendor id sent in the Forward Open originator identity.</summary>
public ushort VendorId { get; init; } = 0x1337;
/// <summary>Random per process; together with the vendor id and connection serial it names a connection.</summary>
public uint OriginatorSerial { get; init; } = ProcessOriginatorSerial;
}