namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT; /// /// Wire-layer abstraction over one connection to a TwinCAT AMS target. One instance per /// ; reused across reads / writes / probes for the device. /// Tests swap in a fake via . /// /// /// Unlike libplctag-backed drivers where one native handle exists per tag, TwinCAT's /// AdsClient is one connection per target with symbolic reads / writes issued against it. /// The abstraction reflects that — single , many /// / calls. /// public interface ITwinCATClient : IDisposable { /// Establish the AMS connection. Idempotent — subsequent calls are no-ops when already connected. Task ConnectAsync(TwinCATAmsAddress address, TimeSpan timeout, CancellationToken cancellationToken); /// True when the AMS router + target both accept commands. bool IsConnected { get; } /// /// Read a symbolic value. Returns a boxed .NET value matching the requested /// , or null when the read produced no data; the /// status tuple member carries the mapped OPC UA status (0 = Good). /// Task<(object? value, uint status)> ReadValueAsync( string symbolPath, TwinCATDataType type, int? bitIndex, CancellationToken cancellationToken); /// /// Write a symbolic value. Returns the mapped OPC UA status for the operation /// (0 = Good, non-zero = error mapped via ). /// Task WriteValueAsync( string symbolPath, TwinCATDataType type, int? bitIndex, object? value, CancellationToken cancellationToken); /// /// Cheap health probe — returns true when the target's AMS state is reachable. /// Used by 's probe loop. /// Task ProbeAsync(CancellationToken cancellationToken); /// /// Register a cyclic / on-change ADS notification for a symbol. Returns a handle whose /// tears the notification down. Callback fires on the /// thread libplctag / AdsClient uses for notifications — consumers should marshal to /// their own scheduler before doing work of any size. /// /// ADS symbol path (e.g. MAIN.bStart). /// Declared type; drives the native layout + callback value boxing. /// For BOOL-within-word tags — the bit to extract from the parent word. /// Minimum interval between change notifications (native-floor depends on target). /// Invoked with (symbolPath, boxedValue) per notification. /// Cancels the initial registration; does not tear down an established notification. Task AddNotificationAsync( string symbolPath, TwinCATDataType type, int? bitIndex, TimeSpan cycleTime, Action onChange, CancellationToken cancellationToken); /// /// Walk the target's symbol table via the TwinCAT SymbolLoaderFactory (flat mode). /// Yields each top-level symbol the PLC exposes — global variables, program-scope locals, /// function-block instance fields. Filters for our atomic type surface; structured / /// UDT / function-block typed symbols surface with DataType = null so callers can /// decide whether to drill in via their own walker. /// IAsyncEnumerable BrowseSymbolsAsync(CancellationToken cancellationToken); } /// Opaque handle for a registered ADS notification. tears it down. public interface ITwinCATNotificationHandle : IDisposable { } /// /// One symbol yielded by — full instance /// path + detected + read-only flag. /// /// Full dotted symbol path (e.g. MAIN.bStart, GVL.Counter). /// Mapped ; null when the symbol's type /// doesn't map onto our supported atomic surface (UDTs, pointers, function blocks). /// true when the symbol's AccessRights flag forbids writes. public sealed record TwinCATDiscoveredSymbol( string InstancePath, TwinCATDataType? DataType, bool ReadOnly); /// Factory for s. One client per device. public interface ITwinCATClientFactory { ITwinCATClient Create(); }