New FocasAreaKind.Diagnostic parsed from DIAG:nnn (whole-CNC) and DIAG:nnn/axis (per-axis), validated against a per-series FocasCapabilityMatrix.DiagnosticRange table (16i: 0-499; 0i-F family: 0-999; 30i/31i/32i: 0-1023; Power Motion i: 0-255; Unknown: permissive per existing matrix convention). IFocasClient gains ReadDiagnosticAsync(diagNumber, axisOrZero, type, ct) with a default returning BadNotSupported so older transport variants degrade gracefully. FwlibFocasClient implements it via a new cnc_rddiag P/Invoke that reuses the IODBPSD struct (same shape as cnc_rdparam). FocasDriver.ReadAsync dispatches Diagnostic addresses through the new path; non-Diagnostic kinds keep the existing ReadAsync route unchanged. Tests: parser positives (DIAG:1031, DIAG:280/2, case-insensitive, zero, axis-8) + negatives (malformed, axis>31), capability matrix boundaries per series, driver-level dispatch verifying axis index threads through, init-time rejection on out-of-range, and BadNotSupported fallback when the wire client doesn't override the default. 266/266 pass in Driver.FOCAS.Tests. Closes #263 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78 lines
3.5 KiB
C#
78 lines
3.5 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS;
|
|
|
|
/// <summary>
|
|
/// FOCAS driver configuration. One instance supports N CNC devices. Per plan decision #144
|
|
/// each device gets its own <c>(DriverInstanceId, HostAddress)</c> bulkhead key at the
|
|
/// Phase 6.1 resilience layer.
|
|
/// </summary>
|
|
public sealed class FocasDriverOptions
|
|
{
|
|
public IReadOnlyList<FocasDeviceOptions> Devices { get; init; } = [];
|
|
public IReadOnlyList<FocasTagDefinition> Tags { get; init; } = [];
|
|
public FocasProbeOptions Probe { get; init; } = new();
|
|
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
|
|
|
/// <summary>
|
|
/// Fixed-tree behaviour knobs (issue #262, plan PR F1-f). Carries the
|
|
/// <c>ApplyFigureScaling</c> toggle that gates the <c>cnc_getfigure</c>
|
|
/// decimal-place division applied to position values before publishing.
|
|
/// </summary>
|
|
public FocasFixedTreeOptions FixedTree { get; init; } = new();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Per-driver fixed-tree options. New installs default <see cref="ApplyFigureScaling"/>
|
|
/// to <c>true</c> so position values surface in user units (mm / inch). Existing
|
|
/// deployments that already published raw scaled integers can flip this to <c>false</c>
|
|
/// for migration parity — the operator-facing concern is that switching the flag
|
|
/// mid-deployment changes the values clients see, so the migration path is
|
|
/// documentation-only (issue #262).
|
|
/// </summary>
|
|
public sealed record FocasFixedTreeOptions
|
|
{
|
|
/// <summary>
|
|
/// When <c>true</c> (default), position values from <c>cnc_absolute</c> /
|
|
/// <c>cnc_machine</c> / <c>cnc_relative</c> / <c>cnc_distance</c> /
|
|
/// <c>cnc_actf</c> are divided by <c>10^decimalPlaces</c> per axis using the
|
|
/// <c>cnc_getfigure</c> snapshot cached at probe time. When <c>false</c>, the
|
|
/// raw integer values are published unchanged — used for migrations from
|
|
/// older drivers that didn't apply the scaling.
|
|
/// </summary>
|
|
public bool ApplyFigureScaling { get; init; } = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// One CNC the driver talks to. <paramref name="Series"/> enables per-series
|
|
/// address validation at <see cref="FocasDriver.InitializeAsync"/>; leave as
|
|
/// <see cref="FocasCncSeries.Unknown"/> to skip validation (legacy behaviour).
|
|
/// <paramref name="OverrideParameters"/> declares the four MTB-specific override
|
|
/// <c>cnc_rdparam</c> numbers surfaced under <c>Override/</c>; pass <c>null</c> to
|
|
/// suppress the entire <c>Override/</c> subfolder for that device (issue #259).
|
|
/// </summary>
|
|
public sealed record FocasDeviceOptions(
|
|
string HostAddress,
|
|
string? DeviceName = null,
|
|
FocasCncSeries Series = FocasCncSeries.Unknown,
|
|
FocasOverrideParameters? OverrideParameters = null);
|
|
|
|
/// <summary>
|
|
/// One FOCAS-backed OPC UA variable. <paramref name="Address"/> is the canonical FOCAS
|
|
/// address string that parses via <see cref="FocasAddress.TryParse"/> —
|
|
/// <c>X0.0</c> / <c>R100</c> / <c>PARAM:1815/0</c> / <c>MACRO:500</c> /
|
|
/// <c>DIAG:1031</c> / <c>DIAG:280/2</c>.
|
|
/// </summary>
|
|
public sealed record FocasTagDefinition(
|
|
string Name,
|
|
string DeviceHostAddress,
|
|
string Address,
|
|
FocasDataType DataType,
|
|
bool Writable = true,
|
|
bool WriteIdempotent = false);
|
|
|
|
public sealed class FocasProbeOptions
|
|
{
|
|
public bool Enabled { get; init; } = true;
|
|
public TimeSpan Interval { get; init; } = TimeSpan.FromSeconds(5);
|
|
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(2);
|
|
}
|