117 lines
6.0 KiB
C#
117 lines
6.0 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||
|
||
/// <summary>
|
||
/// AB CIP / EtherNet-IP driver configuration, bound from the driver's <c>DriverConfig</c>
|
||
/// JSON at <c>DriverHost.RegisterAsync</c>. One instance supports N devices (PLCs) behind
|
||
/// the same driver; per-device routing is keyed on <see cref="AbCipDeviceOptions.HostAddress"/>
|
||
/// via <c>IPerCallHostResolver</c>.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Per v2 plan decisions #11 (libplctag), #41 (AbCip vs AbLegacy split), #143–144 (per-call
|
||
/// host resolver + resilience keys), #144 (bulkhead keyed on <c>(DriverInstanceId, HostName)</c>).
|
||
/// </remarks>
|
||
public sealed class AbCipDriverOptions
|
||
{
|
||
/// <summary>
|
||
/// PLCs this driver instance talks to. Each device contributes its own <see cref="AbCipHostAddress"/>
|
||
/// string as the <c>hostName</c> key used by resilience pipelines and the Admin UI.
|
||
/// </summary>
|
||
public IReadOnlyList<AbCipDeviceOptions> Devices { get; init; } = [];
|
||
|
||
/// <summary>Pre-declared tag map across all devices — AB discovery lands in PR 5.</summary>
|
||
public IReadOnlyList<AbCipTagDefinition> Tags { get; init; } = [];
|
||
|
||
/// <summary>Per-device probe settings. Falls back to defaults when omitted.</summary>
|
||
public AbCipProbeOptions Probe { get; init; } = new();
|
||
|
||
/// <summary>
|
||
/// Default libplctag call timeout applied to reads/writes/discovery when the caller does
|
||
/// not pass a more specific value. Matches the Modbus driver's 2-second default.
|
||
/// </summary>
|
||
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
||
}
|
||
|
||
/// <summary>
|
||
/// One PLC endpoint. <see cref="HostAddress"/> must parse via
|
||
/// <see cref="AbCipHostAddress.TryParse"/>; misconfigured devices fail driver
|
||
/// initialization rather than silently connecting to nothing.
|
||
/// </summary>
|
||
/// <param name="HostAddress">Canonical <c>ab://gateway[:port]/cip-path</c> string.</param>
|
||
/// <param name="PlcFamily">Which per-family profile to apply. Determines ConnectionSize,
|
||
/// request-packing support, unconnected-only hint, and other quirks.</param>
|
||
/// <param name="DeviceName">Optional display label for Admin UI. Falls back to <see cref="HostAddress"/>.</param>
|
||
public sealed record AbCipDeviceOptions(
|
||
string HostAddress,
|
||
AbCipPlcFamily PlcFamily = AbCipPlcFamily.ControlLogix,
|
||
string? DeviceName = null);
|
||
|
||
/// <summary>
|
||
/// One AB-backed OPC UA variable. Mirrors the <c>ModbusTagDefinition</c> shape.
|
||
/// </summary>
|
||
/// <param name="Name">Tag name; becomes the OPC UA browse name and full reference.</param>
|
||
/// <param name="DeviceHostAddress">Which device (<see cref="AbCipDeviceOptions.HostAddress"/>) this tag lives on.</param>
|
||
/// <param name="TagPath">Logix symbolic path (controller or program scope).</param>
|
||
/// <param name="DataType">Logix atomic type, or <see cref="AbCipDataType.Structure"/> for UDT-typed tags.</param>
|
||
/// <param name="Writable">When <c>true</c> and the tag's ExternalAccess permits writes, IWritable routes writes here.</param>
|
||
/// <param name="WriteIdempotent">Per plan decisions #44–#45, #143 — safe to replay on write timeout. Default <c>false</c>.</param>
|
||
/// <param name="Members">For <see cref="AbCipDataType.Structure"/>-typed tags, the declared UDT
|
||
/// member layout. When supplied, discovery fans out the UDT into a folder + one Variable per
|
||
/// member (member TagPath = <c>{tag.TagPath}.{member.Name}</c>). When <c>null</c> on a Structure
|
||
/// tag, the driver treats it as a black-box and relies on downstream configuration to address
|
||
/// members individually via dotted <see cref="AbCipTagPath"/> syntax. Ignored for atomic types.</param>
|
||
/// <param name="SafetyTag">GuardLogix safety-partition tag hint. When <c>true</c>, the driver
|
||
/// forces <c>SecurityClassification.ViewOnly</c> on discovery regardless of
|
||
/// <paramref name="Writable"/> — safety tags can only be written from the safety task of a
|
||
/// GuardLogix controller; non-safety writes violate the safety-partition isolation and are
|
||
/// rejected by the PLC anyway. Surfaces the intent explicitly instead of relying on the
|
||
/// write attempt failing at runtime.</param>
|
||
public sealed record AbCipTagDefinition(
|
||
string Name,
|
||
string DeviceHostAddress,
|
||
string TagPath,
|
||
AbCipDataType DataType,
|
||
bool Writable = true,
|
||
bool WriteIdempotent = false,
|
||
IReadOnlyList<AbCipStructureMember>? Members = null,
|
||
bool SafetyTag = false);
|
||
|
||
/// <summary>
|
||
/// One declared member of a UDT tag. Name is the member identifier on the PLC (e.g. <c>Speed</c>,
|
||
/// <c>Status</c>), DataType is the atomic Logix type, Writable/WriteIdempotent mirror
|
||
/// <see cref="AbCipTagDefinition"/>. Declaration-driven — the real CIP Template Object reader
|
||
/// (class 0x6C) that would auto-discover member layouts lands as a follow-up PR.
|
||
/// </summary>
|
||
public sealed record AbCipStructureMember(
|
||
string Name,
|
||
AbCipDataType DataType,
|
||
bool Writable = true,
|
||
bool WriteIdempotent = false);
|
||
|
||
/// <summary>Which AB PLC family the device is — selects the profile applied to connection params.</summary>
|
||
public enum AbCipPlcFamily
|
||
{
|
||
ControlLogix,
|
||
CompactLogix,
|
||
Micro800,
|
||
GuardLogix,
|
||
}
|
||
|
||
/// <summary>
|
||
/// Background connectivity-probe settings. Enabled by default; the probe reads a cheap tag
|
||
/// on the PLC at the configured interval to drive <see cref="Core.Abstractions.IHostConnectivityProbe"/>
|
||
/// state transitions + Admin UI health status.
|
||
/// </summary>
|
||
public sealed class AbCipProbeOptions
|
||
{
|
||
public bool Enabled { get; init; } = true;
|
||
public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5);
|
||
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
||
|
||
/// <summary>
|
||
/// Tag path used for the probe. If null, the driver attempts to read a default
|
||
/// system tag (PR 8 wires this up — the choice is family-dependent, e.g.
|
||
/// <c>@raw_cpu_type</c> on ControlLogix or a user-configured probe tag on Micro800).
|
||
/// </summary>
|
||
public string? ProbeTagPath { get; init; }
|
||
}
|