Files
lmxopcua/src/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Cli/AbCipCommandBase.cs
T
2026-04-26 07:51:44 -04:00

97 lines
4.6 KiB
C#

using CliFx.Attributes;
using ZB.MOM.WW.OtOpcUa.Driver.Cli.Common;
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.Cli;
/// <summary>
/// Base for every AB CIP CLI command. Carries the libplctag endpoint options
/// (<c>--gateway</c> + <c>--family</c>) and exposes <see cref="BuildOptions"/> so each
/// command can synthesise an <see cref="AbCipDriverOptions"/> from CLI flags + its own
/// tag list.
/// </summary>
public abstract class AbCipCommandBase : DriverCommandBase
{
[CommandOption("gateway", 'g', Description =
"Canonical AB CIP gateway: ab://host[:port]/cip-path. Port defaults to 44818 " +
"(EtherNet/IP). cip-path is family-specific: ControlLogix / CompactLogix need " +
"'1,0' to reach slot 0 of the CPU chassis; Micro800 takes an empty path; " +
"GuardLogix typically '1,0' same as ControlLogix.",
IsRequired = true)]
public string Gateway { get; init; } = default!;
[CommandOption("family", 'f', Description =
"ControlLogix / CompactLogix / Micro800 / GuardLogix (default ControlLogix).")]
public AbCipPlcFamily Family { get; init; } = AbCipPlcFamily.ControlLogix;
[CommandOption("timeout-ms", Description = "Per-operation timeout in ms (default 5000).")]
public int TimeoutMs { get; init; } = 5000;
/// <summary>
/// PR abcip-3.2 — pin the device's CIP addressing mode for this CLI invocation.
/// Auto / Symbolic / Logical. Defaults to <see cref="AddressingMode.Auto"/> (resolves
/// to Symbolic until a future PR plumbs auto-detection). Logical against an
/// unsupported family (Micro800) silently falls back to Symbolic with a logged
/// warning, so passing <c>--addressing-mode Logical</c> across a mixed-family
/// fleet is safe.
/// </summary>
[CommandOption("addressing-mode", Description =
"CIP addressing mode: Auto / Symbolic / Logical (default Auto, resolves to " +
"Symbolic). Logical uses CIP Symbol Object instance IDs after a one-time @tags " +
"walk; unsupported on Micro800 (silent fallback to Symbolic with warning).")]
public AddressingMode AddressingMode { get; init; } = AddressingMode.Auto;
/// <summary>
/// PR abcip-5.1 — partner gateway URI for HSBY (Hot-Standby) paired chassis. When
/// supplied, every CLI command auto-enables HSBY role probing on the device options
/// so subcommands like <c>hsby-status</c> + diagnostics surface the active chassis
/// without extra flags. Unset for non-redundant deployments.
/// </summary>
[CommandOption("partner", Description =
"Partner gateway URI for ControlLogix HSBY pair (e.g. ab://10.0.0.6/1,0). When " +
"set, the driver runs a second role-probe loop and the hsby-status command can " +
"surface which chassis is currently Active. Optional.")]
public string? Partner { get; init; }
/// <inheritdoc />
public override TimeSpan Timeout
{
get => TimeSpan.FromMilliseconds(TimeoutMs);
init { /* driven by TimeoutMs */ }
}
/// <summary>
/// Build an <see cref="AbCipDriverOptions"/> with the device + tag list a subclass
/// supplies. Probe + alarm projection are disabled — CLI runs are one-shot; the
/// probe loop would race the operator's own reads.
/// </summary>
protected AbCipDriverOptions BuildOptions(IReadOnlyList<AbCipTagDefinition> tags) => new()
{
Devices = [new AbCipDeviceOptions(
HostAddress: Gateway,
PlcFamily: Family,
DeviceName: $"cli-{Family}",
AddressingMode: AddressingMode,
// PR abcip-5.1 — surface --partner through the device options so commands that
// use BuildOptions can take advantage of HSBY role probing without subclassing.
// Hsby auto-enables only when a partner was actually supplied; pre-5.1 invocations
// (no --partner) see exactly the legacy options shape.
PartnerHostAddress: Partner,
Hsby: string.IsNullOrWhiteSpace(Partner) ? null : new AbCipHsbyOptions
{
Enabled = true,
ProbeInterval = TimeSpan.FromSeconds(2),
})],
Tags = tags,
Timeout = Timeout,
Probe = new AbCipProbeOptions { Enabled = false },
EnableControllerBrowse = false,
EnableAlarmProjection = false,
};
/// <summary>
/// Short instance id used in Serilog output so operators running the CLI against
/// multiple gateways in parallel can distinguish the logs.
/// </summary>
protected string DriverInstanceId => $"abcip-cli-{Gateway}";
}