feat(twincat): expand discovered struct/UDT symbols into addressable member leaves
This commit is contained in:
@@ -326,7 +326,12 @@ internal sealed class AdsTwinCATClient : ITwinCATClient
|
||||
var loader = SymbolLoaderFactory.Create(_client, settings);
|
||||
await Task.Yield(); // honors the async surface; pragmatic given the loader itself is sync
|
||||
|
||||
foreach (ISymbol symbol in loader.Symbols)
|
||||
// Expand struct/UDT/FB-instance symbols down to their addressable atomic members via the
|
||||
// pure TwinCATSymbolExpander (unit-proven; the real ISymbol surface is non-injectable so the
|
||||
// recursion is tested through the ITwinCATSymbolNode abstraction, then adapted here). The
|
||||
// expander dedups by InstancePath, so it also neutralizes any Flat-vs-tree double-listing.
|
||||
foreach (var ds in TwinCATSymbolExpander.ExpandLeaves(
|
||||
loader.Symbols.Select(s => new AdsSymbolNode(s))))
|
||||
{
|
||||
// ThrowIfCancellationRequested — not yield break — so a cancelled browse propagates
|
||||
// as OperationCanceledException rather than a silent clean completion. DiscoverAsync
|
||||
@@ -334,12 +339,33 @@ internal sealed class AdsTwinCATClient : ITwinCATClient
|
||||
// distinctly from a genuine browse failure; a yield break would let a partial
|
||||
// symbol set appear as a fully successful discovery (Driver.TwinCAT-010).
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var (mapped, arrayLength) = MapSymbolType(symbol.DataType);
|
||||
var readOnly = !IsSymbolWritable(symbol);
|
||||
yield return new TwinCATDiscoveredSymbol(symbol.InstancePath, mapped, readOnly, arrayLength);
|
||||
yield return ds;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adapts Beckhoff's <see cref="ISymbol"/> onto <see cref="ITwinCATSymbolNode"/> so the pure
|
||||
/// <see cref="TwinCATSymbolExpander"/> can walk it. Children are materialized eagerly per node
|
||||
/// (the loader has already downloaded the whole symbol-info blob, so descending sub-symbols is
|
||||
/// a local operation). Reuses the existing <see cref="MapSymbolType"/> + <see cref="IsSymbolWritable"/>
|
||||
/// so atomic-type mapping and access-rights handling stay identical to the pre-expansion path.
|
||||
/// </summary>
|
||||
private sealed class AdsSymbolNode(ISymbol symbol) : ITwinCATSymbolNode
|
||||
{
|
||||
public string InstancePath => symbol.InstancePath;
|
||||
|
||||
public bool IsStruct => symbol.DataType?.Category == DataTypeCategory.Struct;
|
||||
|
||||
public (TwinCATDataType? Type, int? ArrayLength) Mapped => MapSymbolType(symbol.DataType);
|
||||
|
||||
public IReadOnlyList<ITwinCATSymbolNode> Children =>
|
||||
symbol.SubSymbols is { } subs
|
||||
? subs.Select(s => (ITwinCATSymbolNode)new AdsSymbolNode(s)).ToList()
|
||||
: [];
|
||||
|
||||
public bool ReadOnly => !IsSymbolWritable(symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a symbol's <see cref="IDataType"/> to the driver's atomic
|
||||
/// <see cref="TwinCATDataType"/> plus an optional 1-D array length.
|
||||
|
||||
Reference in New Issue
Block a user