Auto: abcip-5.1 — HSBY paired-IP role probing

Closes #242
This commit is contained in:
Joseph Doherty
2026-04-26 07:51:44 -04:00
parent 349aa5c6f4
commit 561b0f9ea9
12 changed files with 1260 additions and 9 deletions

View File

@@ -151,6 +151,23 @@ public sealed class AbCipDriverOptions
/// where the wire-cost of one whole-UDT read still beats N member reads on ControlLogix's
/// 4002-byte connection size; see <c>docs/drivers/AbCip-Performance.md</c> §"Read strategy".
/// Clamped to <c>[0..1]</c> at planner time; values outside the range silently saturate.</param>
/// <param name="PartnerHostAddress">PR abcip-5.1 — optional canonical AB CIP gateway URI of the
/// partner chassis in a ControlLogix HSBY (Hot-Standby) pair. When set together with
/// <paramref name="Hsby"/><c>.Enabled = true</c>, the driver runs a second probe loop against
/// this partner address + uses the configured role tag (default
/// <c>WallClockTime.SyncStatus</c>, fall-back <c>S:34</c> for PLC-5 / SLC-style fronts) to
/// determine which chassis is currently Active. PR abcip-5.1 only **discovers + reports**
/// the active chassis through driver diagnostics; PR abcip-5.2 is the follow-up that wires
/// the resolved active address into <see cref="AbCipDriver.ResolveHost"/> for live read /
/// write routing. <c>null</c> = no HSBY partner; the driver behaves exactly like every
/// pre-5.1 build.</param>
/// <param name="Hsby">PR abcip-5.1 — HSBY (Hot-Standby) sub-options. Defaults to
/// <c>Enabled = false</c> so back-compat deployments that don't set
/// <see cref="PartnerHostAddress"/> see no behaviour change. <see cref="AbCipHsbyOptions.Enabled"/>
/// gates the second probe loop + role-tag read; <see cref="AbCipHsbyOptions.RoleTagAddress"/>
/// picks <c>WallClockTime.SyncStatus</c> (v20+ ControlLogix) vs <c>S:34</c> (legacy
/// SLC500 / PLC-5 status byte fallback); <see cref="AbCipHsbyOptions.ProbeInterval"/>
/// controls the role-tag poll cadence.</param>
public sealed record AbCipDeviceOptions(
string HostAddress,
AbCipPlcFamily PlcFamily = AbCipPlcFamily.ControlLogix,
@@ -158,7 +175,52 @@ public sealed record AbCipDeviceOptions(
int? ConnectionSize = null,
AddressingMode AddressingMode = AddressingMode.Auto,
ReadStrategy ReadStrategy = ReadStrategy.Auto,
double MultiPacketSparsityThreshold = 0.25);
double MultiPacketSparsityThreshold = 0.25,
string? PartnerHostAddress = null,
AbCipHsbyOptions? Hsby = null);
/// <summary>
/// PR abcip-5.1 — HSBY (Hot-Standby) per-device options. Off by default. When
/// <see cref="Enabled"/> = <c>true</c> + the device sets
/// <see cref="AbCipDeviceOptions.PartnerHostAddress"/>, the driver runs two probe loops
/// concurrently — primary <see cref="AbCipDeviceOptions.HostAddress"/> + the partner —
/// reads the configured role tag on each, and reports which chassis is Active through
/// driver diagnostics (<c>AbCip.HsbyActive</c>, <c>AbCip.HsbyPrimaryRole</c>,
/// <c>AbCip.HsbyPartnerRole</c>). PR abcip-5.2 is the follow-up that wires the resolved
/// active address back into <see cref="AbCipDriver.ResolveHost"/> for live read / write
/// routing — 5.1 just gathers the role.
/// </summary>
/// <remarks>
/// Role-tag detection matrix:
/// <list type="bullet">
/// <item><b>v20 / v24 / v32+ ControlLogix HSBY</b> — <c>WallClockTime.SyncStatus</c>
/// (DINT). Values: <c>0</c> = Standby (Synchronized but not Active),
/// <c>1</c> = Synchronized / Active (active chassis), <c>2</c> = Disqualified.</item>
/// <item><b>PLC-5 / SLC500 fallback</b> — <c>S:34</c> Module Status word (PLC-5 has a
/// role bit in word 34 of the status file). Bit 0 = "this chassis is Active". This
/// is the legacy fallback for sites that haven't migrated to ControlLogix HSBY.</item>
/// </list>
/// </remarks>
public sealed record AbCipHsbyOptions
{
/// <summary>Master switch. Default <c>false</c> — no role probing, no second probe loop.</summary>
public bool Enabled { get; init; }
/// <summary>
/// Address of the role tag the driver reads on each probe tick. Default
/// <c>WallClockTime.SyncStatus</c> matches v20+ ControlLogix HSBY firmware. Legacy
/// PLC-5 / SLC500 fronts that expose a status-file role bit pass <c>S:34</c> here +
/// the role prober applies the bit-mask interpretation automatically.
/// </summary>
public string RoleTagAddress { get; init; } = "WallClockTime.SyncStatus";
/// <summary>
/// Cadence the HSBY role probe ticks at. Default 2 seconds — tight enough to detect
/// a manual switch-over within one Admin-UI refresh, loose enough to leave headroom
/// for the regular probe loop on the same gateway.
/// </summary>
public TimeSpan ProbeInterval { get; init; } = TimeSpan.FromSeconds(2);
}
/// <summary>
/// PR abcip-3.3 — per-device strategy for reading multi-member UDT batches. <see cref="WholeUdt"/>