using CliFx.Attributes; using ZB.MOM.WW.OtOpcUa.Driver.Cli.Common; namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Cli; /// /// Base for every FOCAS CLI command. Carries the CNC endpoint options /// (host / port / series) + exposes so each command /// can synthesise a with one device + one tag. /// public abstract class FocasCommandBase : DriverCommandBase { [CommandOption("cnc-host", 'h', Description = "CNC IP address or hostname. FOCAS-over-EIP listens on port 8193 by default.", IsRequired = true)] public string CncHost { get; init; } = default!; [CommandOption("cnc-port", 'p', Description = "FOCAS TCP port (default 8193).")] public int CncPort { get; init; } = 8193; [CommandOption("series", 's', Description = "CNC series: Unknown / Zero_i_D / Zero_i_F / Zero_i_MF / Zero_i_TF / Sixteen_i / " + "Thirty_i / ThirtyOne_i / ThirtyTwo_i / PowerMotion_i (default Unknown).")] public FocasCncSeries Series { get; init; } = FocasCncSeries.Unknown; [CommandOption("timeout-ms", Description = "Per-operation timeout in ms (default 2000).")] public int TimeoutMs { get; init; } = 2000; /// /// Plan PR F4-d (issue #271) — optional CNC connection-level password emitted /// via cnc_wrunlockparam on connect. Required only by controllers that /// gate cnc_wrparam + selected reads behind a password switch. /// PASSWORD INVARIANT: never logged. The CLI's Serilog config does not /// include this option in any console / file destructure; the redaction is /// enforced at the layer (record's /// overridden ToString). /// [CommandOption("cnc-password", Description = "Optional CNC connection password emitted via cnc_wrunlockparam on connect. " + "Required by controllers that gate parameter writes behind a password switch.")] public string? CncPassword { get; init; } /// public override TimeSpan Timeout { get => TimeSpan.FromMilliseconds(TimeoutMs); init { /* driven by TimeoutMs */ } } /// Canonical FOCAS host-address string, shape focas://host:port. protected string HostAddress => $"focas://{CncHost}:{CncPort}"; /// /// Build a with the CNC target this base collected /// + the tag list a subclass supplies. Probe disabled; the default /// attempts Fwlib32.dll P/Invoke, which /// throws at first call when the DLL is absent — /// surfaced through the driver as BadCommunicationError. Pass /// = true to bypass the F4-a driver-level /// write gate for the lifetime of this CLI invocation (issue #268). /// protected FocasDriverOptions BuildOptions( IReadOnlyList tags, bool writesEnabled = false) => new() { Devices = [new FocasDeviceOptions( HostAddress: HostAddress, DeviceName: $"cli-{CncHost}:{CncPort}", Series: Series, OverrideParameters: null, // PR F4-d (issue #271) — thread the CLI's --cnc-password through to // the driver. Null when the operator didn't supply the flag — the // driver short-circuits the unlock call in that case. Password: CncPassword)], Tags = tags, Timeout = Timeout, Probe = new FocasProbeOptions { Enabled = false }, Writes = new FocasWritesOptions { Enabled = writesEnabled }, }; protected string DriverInstanceId => $"focas-cli-{CncHost}:{CncPort}"; }