feat(focas): resolve equipment-tag refs (read + write) via EquipmentTagRefResolver

This commit is contained in:
Joseph Doherty
2026-06-13 11:24:45 -04:00
parent 5ebf541f54
commit 34a42486dc
3 changed files with 126 additions and 2 deletions
@@ -27,6 +27,10 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
private readonly ILogger<FocasDriver> _logger;
private readonly Dictionary<string, DeviceState> _devices = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, FocasTagDefinition> _tagsByName = new(StringComparer.OrdinalIgnoreCase);
// Resolves a read/write fullReference to a tag definition, bridging the two authoring
// models: an authored tag-table entry (by name) OR an equipment tag whose reference is
// its raw TagConfig JSON (parsed once via FocasEquipmentTagParser, cached).
private readonly EquipmentTagRefResolver<FocasTagDefinition> _resolver;
// Per-tag-name cache of the FocasAddress parsed once at InitializeAsync. ReadAsync /
// WriteAsync look up the pre-parsed value instead of re-parsing tag.Address on every hot
// call — resolves Driver.FOCAS-008.
@@ -59,6 +63,9 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
_driverInstanceId = driverInstanceId;
_clientFactory = clientFactory ?? new Wire.WireFocasClientFactory();
_logger = logger ?? NullLogger<FocasDriver>.Instance;
_resolver = new EquipmentTagRefResolver<FocasTagDefinition>(
r => _tagsByName.TryGetValue(r, out var t) ? t : null,
r => FocasEquipmentTagParser.TryParse(r, out var d) ? d : null);
_poll = new PollGroupEngine(
reader: ReadAsync,
onChange: (handle, tagRef, snapshot) =>
@@ -198,6 +205,7 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
}
_devices.Clear();
_tagsByName.Clear();
_resolver.Clear(); // drop transient equipment-tag parses so a config change re-parses
_parsedAddressesByTagName.Clear();
Volatile.Write(ref _health, new DriverHealth(DriverState.Unknown, Volatile.Read(ref _health).LastSuccessfulRead, null));
}
@@ -248,7 +256,7 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
continue;
}
if (!_tagsByName.TryGetValue(reference, out var def))
if (!_resolver.TryResolve(reference, out var def))
{
results[i] = new DataValueSnapshot(null, FocasStatusMapper.BadNodeIdUnknown, null, now);
continue;
@@ -307,7 +315,7 @@ public sealed class FocasDriver : IDriver, IReadable, IWritable, ITagDiscovery,
for (var i = 0; i < writes.Count; i++)
{
var w = writes[i];
if (!_tagsByName.TryGetValue(w.FullReference, out var def))
if (!_resolver.TryResolve(w.FullReference, out var def))
{
results[i] = new WriteResult(FocasStatusMapper.BadNodeIdUnknown);
continue;